From bb40f1d8e886f08039abb0be4360fc31681f54a6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 10 Nov 2017 17:52:02 -0500 Subject: [PATCH 01/34] 3202 Messaging for changing of status which tag implies --- .../sleuthkit/autopsy/casemodule/Case.java | 12 ++- .../services/TagNameDefinition.java | 18 ++-- .../casemodule/services/TagNameDialog.java | 3 +- .../casemodule/services/TagOptionsPanel.java | 11 ++- .../casemodule/services/TagsManager.java | 2 +- .../eventlisteners/CaseEventListener.java | 95 ++++++++++++++++++- 6 files changed, 122 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 983c9420b2..1cadd0b0b2 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -76,6 +76,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent; import org.sleuthkit.autopsy.casemodule.services.Services; +import org.sleuthkit.autopsy.casemodule.services.TagNameDefinition; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CategoryNode; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; @@ -362,7 +363,13 @@ public class Case { * case number, the examiner name, examiner phone, examiner email, and * the case notes. */ - CASE_DETAILS; + CASE_DETAILS, + /** + * The status which a Tag indicates has been changed and the new value + * of the TagNameDefinition is included. + */ + TAG_STATUS_CHANGED; + }; /** @@ -1472,6 +1479,9 @@ public class Case { eventPublisher.publish(new ContentTagDeletedEvent(deletedTag)); } + public void notifyTagStatusChanged(TagNameDefinition oldTag, TagNameDefinition newTag) { + eventPublisher.publish(new AutopsyEvent(Events.TAG_STATUS_CHANGED.toString(), oldTag, newTag)); + } /** * Notifies case event subscribers that an artifact tag has been added. * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index 7dd4b5309a..f039a40d92 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -34,7 +34,7 @@ import org.sleuthkit.datamodel.TskData; * A tag name definition consisting of a display name, description and color. */ @Immutable -final class TagNameDefinition implements Comparable { +public final class TagNameDefinition implements Comparable { private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS @@ -58,7 +58,8 @@ final class TagNameDefinition implements Comparable { * @param knownStatus The status denoted by the tag. */ - TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { + public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { + this.displayName = displayName; this.description = description; this.color = color; @@ -70,7 +71,7 @@ final class TagNameDefinition implements Comparable { * * @return The display name. */ - String getDisplayName() { + public String getDisplayName() { return displayName; } @@ -92,14 +93,9 @@ final class TagNameDefinition implements Comparable { return color; } - /** - * Whether or not the status that this tag implies is the Notable status - * - * @return true if the Notable status is implied by this tag, false - * otherwise. - */ - boolean isNotable() { - return knownStatusDenoted == TskData.FileKnown.BAD; + + public TskData.FileKnown getKnownStatus() { + return knownStatusDenoted; } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java index e310c066e5..402c3b1a09 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java @@ -29,6 +29,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.datamodel.TskData; final class TagNameDialog extends javax.swing.JDialog { @@ -59,7 +60,7 @@ final class TagNameDialog extends javax.swing.JDialog { initComponents(); tagNameTextField.setText(tagNameToEdit.getDisplayName()); descriptionTextArea.setText(tagNameToEdit.getDescription()); - notableCheckbox.setSelected(tagNameToEdit.isNotable()); + notableCheckbox.setSelected(tagNameToEdit.getKnownStatus()== TskData.FileKnown.BAD); tagNameTextField.setEnabled(false); this.display(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index 6505fec9df..082827a94a 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -28,6 +28,7 @@ import javax.swing.JOptionPane; import javax.swing.event.ListSelectionEvent; import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.TagName; @@ -46,7 +47,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private IngestJobEventPropertyChangeListener ingestJobEventsListener; /** - * Creates new form TagsManagerOptionsPanel + * Creates new form TagOptionsPanel */ TagOptionsPanel() { tagTypesListModel = new DefaultListModel<>(); @@ -336,14 +337,16 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { TagNameDefinition newTagType = new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status); /* * If tag name already exists, don't add the tag name. - */ - + */ tagTypes.remove(originalTagName); tagTypes.add(newTagType); updateTagNamesListModel(); tagNamesList.setSelectedValue(newTagType, true); updatePanel(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + if (originalTagName.getKnownStatus() != newTagType.getKnownStatus() && Case.isCaseOpen()){ + Case.getCurrentCase().notifyTagStatusChanged(originalTagName,newTagType); + } } }//GEN-LAST:event_editTagNameButtonActionPerformed @@ -416,7 +419,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { if (isSelected) { descriptionTextArea.setText(tagNamesList.getSelectedValue().getDescription()); - if (tagNamesList.getSelectedValue().isNotable()) { + if (tagNamesList.getSelectedValue().getKnownStatus() == TskData.FileKnown.BAD) { notableYesOrNoLabel.setText("Yes"); } else { notableYesOrNoLabel.setText("No"); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 6dd4d359c3..d2dc7deea4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -136,7 +136,7 @@ public class TagsManager implements Closeable { public static List getNotableTagDisplayNames() { List tagDisplayNames = new ArrayList<>(); for (TagNameDefinition tagDef : TagNameDefinition.getTagNameDefinitions()) { - if (tagDef.isNotable()) { + if (tagDef.getKnownStatus() == TskData.FileKnown.BAD) { tagDisplayNames.add(tagDef.getDisplayName()); } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index dbe17d6e6d..064f04fd78 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent; +import org.sleuthkit.autopsy.casemodule.services.TagNameDefinition; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; @@ -48,6 +49,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskDataException; @@ -97,6 +99,10 @@ final class CaseEventListener implements PropertyChangeListener { jobProcessingExecutor.submit(new DataSourceAddedTask(dbManager, evt)); } break; + case TAG_STATUS_CHANGED: { + //WJS-TODO actaully do stuff when event is seen. + jobProcessingExecutor.submit(new TagStatusChangeTask(dbManager, evt)); + } case CURRENT_CASE: { jobProcessingExecutor.submit(new CurrentCaseTask(dbManager, evt)); @@ -294,6 +300,93 @@ final class CaseEventListener implements PropertyChangeListener { } + private final class TagStatusChangeTask implements Runnable { + + private final EamDb dbManager; + private final PropertyChangeEvent event; + + private TagStatusChangeTask(EamDb db, PropertyChangeEvent evt) { + dbManager = db; + event = evt; + } + + @Override + public void run() { + if (!EamDb.isEnabled()) { + return; + } + TskData.FileKnown status = ((TagNameDefinition) event.getNewValue()).getKnownStatus(); + /** + * Set knownBad status for all files/artifacts in the given case + * that are tagged with the given tag name. Files/artifacts that are + * not already in the database will be added. + * + * @param tagName The name of the tag to search for + * @param curCase The case to search in + */ + try { + TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(((TagNameDefinition) event.getNewValue()).getDisplayName()); + // First find any matching artifacts + List artifactTags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName); + List notableTags = TagsManager.getNotableTagDisplayNames(); + for (BlackboardArtifactTag bbTag : artifactTags) { + List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true); + for (CorrelationAttribute eamArtifact : convertedArtifacts) { + if (status == TskData.FileKnown.UNKNOWN) { + Content content = bbTag.getContent(); + BlackboardArtifact bbArtifact = bbTag.getArtifact(); + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); + if (!(tags.stream() + .map(tag -> tag.getName().getDisplayName()) + .filter(notableTags::contains) + .collect(Collectors.toList()) + .isEmpty())) { // There are more bad tags on the object + break; + } + if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) { + break; + } + } + System.out.println( + "TAG " + ((TagNameDefinition) event.getNewValue()).getDisplayName() + " event FROM " + ((TagNameDefinition) event.getOldValue()).getKnownStatus() + " TO " + ((TagNameDefinition) event.getNewValue()).getKnownStatus()); + EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, status); + } + } + + // Now search for files + List fileTags = Case.getCurrentCase().getSleuthkitCase().getContentTagsByTagName(tagName); + for (ContentTag contentTag : fileTags) { + if (status == TskData.FileKnown.UNKNOWN) { + Content content = contentTag.getContent(); + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + List tags = tagsManager.getContentTagsByContent(content); + if (!(tags.stream() + .map(tag -> tag.getName().getDisplayName()) + .filter(notableTags::contains) + .collect(Collectors.toList()) + .isEmpty())) { // There are more bad tags on the object + continue; + } + } + System.out.println("MAKING ARTIFACT"); + final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(contentTag.getContent(), + TskData.FileKnown.BAD, ""); + if (eamArtifact != null) { + EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, status); + System.out.println( + "TAG " + ((TagNameDefinition) event.getNewValue()).getDisplayName() + " event FROM " + ((TagNameDefinition) event.getOldValue()).getKnownStatus() + " TO " + ((TagNameDefinition) event.getNewValue()).getKnownStatus()); + } + } + } catch (TskCoreException ex) { + System.out.println("Cannot update "); + } catch (EamDbException ex) { + System.out.println("Cannot get CR"); + } + + } //TAG_STATUS_CHANGED + } + private final class DataSourceAddedTask implements Runnable { private final EamDb dbManager; @@ -350,7 +443,7 @@ final class CaseEventListener implements PropertyChangeListener { if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) { Case curCase = (Case) event.getNewValue(); IngestEventsListener.resetCeModuleInstanceCount(); - + CorrelationCase curCeCase = new CorrelationCase( -1, curCase.getName(), // unique case ID From 9b7ada8f64f63d1e2e571ffae6bd92c682a89798 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Nov 2017 17:32:11 -0500 Subject: [PATCH 02/34] 3202 remove confirmation for changing tag status in current case --- .../services/TagNameDefinition.java | 7 +- .../casemodule/services/TagOptionsPanel.java | 68 +++++++++++++++++-- .../services/TagsOptionsPanelController.java | 1 + .../eventlisteners/CaseEventListener.java | 68 +++++++++---------- 4 files changed, 99 insertions(+), 45 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index f039a40d92..38581aa83f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -57,7 +57,6 @@ public final class TagNameDefinition implements Comparable { * @param color The color for the tag name. * @param knownStatus The status denoted by the tag. */ - public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { this.displayName = displayName; @@ -93,7 +92,6 @@ public final class TagNameDefinition implements Comparable { return color; } - public TskData.FileKnown getKnownStatus() { return knownStatusDenoted; } @@ -139,8 +137,9 @@ public final class TagNameDefinition implements Comparable { if (!(obj instanceof TagNameDefinition)) { return false; } - TagNameDefinition thatTagName = (TagNameDefinition) obj; - return this.getDisplayName().equals(thatTagName.getDisplayName()); + boolean sameName = this.getDisplayName().equals(((TagNameDefinition) obj).getDisplayName()); + boolean sameStatus = this.getKnownStatus().equals(((TagNameDefinition) obj).getKnownStatus()); + return sameName && sameStatus; } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index 082827a94a..02f3b925fb 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.services; import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.HashSet; import java.util.Set; import java.util.TreeSet; import javax.swing.DefaultListModel; @@ -28,6 +29,7 @@ import javax.swing.JOptionPane; import javax.swing.event.ListSelectionEvent; import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -40,11 +42,11 @@ import org.sleuthkit.datamodel.TskData; final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private static final long serialVersionUID = 1L; - private static final String DEFAULT_DESCRIPTION = ""; private static final TagName.HTML_COLOR DEFAULT_COLOR = TagName.HTML_COLOR.NONE; private final DefaultListModel tagTypesListModel; private Set tagTypes; private IngestJobEventPropertyChangeListener ingestJobEventsListener; + private Set updatedStatusTags; /** * Creates new form TagOptionsPanel @@ -52,6 +54,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { TagOptionsPanel() { tagTypesListModel = new DefaultListModel<>(); tagTypes = new TreeSet<>(TagNameDefinition.getTagNameDefinitions()); + updatedStatusTags = new HashSet<>(); initComponents(); customizeComponents(); } @@ -295,12 +298,15 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { ); }// //GEN-END:initComponents + @Messages({"TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists.", + "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name"}) + private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagNameButtonActionPerformed TagNameDialog dialog = new TagNameDialog(); TagNameDialog.BUTTON_PRESSED result = dialog.getResult(); if (result == TagNameDialog.BUTTON_PRESSED.OK) { TskData.FileKnown status = dialog.isTagNotable() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN; - TagNameDefinition newTagType = new TagNameDefinition(dialog.getTagName(), DEFAULT_DESCRIPTION, DEFAULT_COLOR, status); + TagNameDefinition newTagType = new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status); /* * If tag name already exists, don't add the tag name. */ @@ -312,8 +318,8 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } else { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(TagOptionsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message"), - NbBundle.getMessage(TagOptionsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title"), + NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message"), + NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title"), JOptionPane.INFORMATION_MESSAGE); } } @@ -337,15 +343,15 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { TagNameDefinition newTagType = new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status); /* * If tag name already exists, don't add the tag name. - */ + */ tagTypes.remove(originalTagName); tagTypes.add(newTagType); updateTagNamesListModel(); tagNamesList.setSelectedValue(newTagType, true); updatePanel(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - if (originalTagName.getKnownStatus() != newTagType.getKnownStatus() && Case.isCaseOpen()){ - Case.getCurrentCase().notifyTagStatusChanged(originalTagName,newTagType); + if (originalTagName.getKnownStatus() != newTagType.getKnownStatus() && Case.isCaseOpen()) { + updatedStatusTags.add(new TagPair(originalTagName, newTagType)); } } }//GEN-LAST:event_editTagNameButtonActionPerformed @@ -398,6 +404,18 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { @Override public void store() { TagNameDefinition.setTagNameDefinitions(tagTypes); + sendStatusChangedEvents(); + } + + void cancelChanges() { + updatedStatusTags.clear(); + } + + private void sendStatusChangedEvents() { + for (TagPair modifiedTag : updatedStatusTags) { + Case.getCurrentCase().notifyTagStatusChanged(modifiedTag.getOldValue(), modifiedTag.getNewValue()); + } + updatedStatusTags.clear(); } /** @@ -440,6 +458,42 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { super.finalize(); } + private class TagPair implements Comparable { + + private TagNameDefinition oldValue; + private TagNameDefinition newValue; + + private TagPair(TagNameDefinition oldV, TagNameDefinition newV) { + oldValue = oldV; + newValue = newV; + } + + private TagNameDefinition getOldValue() { + return oldValue; + } + + private TagNameDefinition getNewValue() { + return newValue; + } + + /** + * Compares this tag name definition with the specified tag name + * definition for order. + * + * @param other The tag name definition to which to compare this tag + * name definition. + * + * @return Negative integer, zero, or a positive integer to indicate + * that this tag name definition is less than, equal to, or + * greater than the specified tag name definition. + */ + @Override + public int compareTo(TagPair other) { + return this.getNewValue().compareTo(other.getNewValue()); + } + + } + /** * A property change listener that listens to ingest job events. */ diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java index c27835f83a..fcd2131f90 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java @@ -69,6 +69,7 @@ public final class TagsOptionsPanelController extends OptionsPanelController { */ @Override public void cancel() { + getPanel().cancelChanges(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 064f04fd78..6ecc0edb4a 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -100,10 +100,9 @@ final class CaseEventListener implements PropertyChangeListener { } break; case TAG_STATUS_CHANGED: { - //WJS-TODO actaully do stuff when event is seen. jobProcessingExecutor.submit(new TagStatusChangeTask(dbManager, evt)); } - + break; case CURRENT_CASE: { jobProcessingExecutor.submit(new CurrentCaseTask(dbManager, evt)); } @@ -318,12 +317,9 @@ final class CaseEventListener implements PropertyChangeListener { TskData.FileKnown status = ((TagNameDefinition) event.getNewValue()).getKnownStatus(); /** * Set knownBad status for all files/artifacts in the given case - * that are tagged with the given tag name. Files/artifacts that are - * not already in the database will be added. - * - * @param tagName The name of the tag to search for - * @param curCase The case to search in + * that are tagged with the given tag name. */ + System.out.println("TAG " + ((TagNameDefinition) event.getNewValue()).getDisplayName() + " event FROM " + ((TagNameDefinition) event.getOldValue()).getKnownStatus().toString() + " TO " + status.toString()); try { TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(((TagNameDefinition) event.getNewValue()).getDisplayName()); // First find any matching artifacts @@ -332,50 +328,54 @@ final class CaseEventListener implements PropertyChangeListener { for (BlackboardArtifactTag bbTag : artifactTags) { List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true); for (CorrelationAttribute eamArtifact : convertedArtifacts) { + boolean hasOtherBadTags = false; if (status == TskData.FileKnown.UNKNOWN) { Content content = bbTag.getContent(); - BlackboardArtifact bbArtifact = bbTag.getArtifact(); - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); - if (!(tags.stream() - .map(tag -> tag.getName().getDisplayName()) - .filter(notableTags::contains) - .collect(Collectors.toList()) - .isEmpty())) { // There are more bad tags on the object - break; - } if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) { break; } + BlackboardArtifact bbArtifact = bbTag.getArtifact(); + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); + for (BlackboardArtifactTag t : tags) { + if (t.getName().equals(tagName)) { + continue; + } + if (notableTags.contains(t.getName().getDisplayName())) { + hasOtherBadTags = true; + break; + } + } + } + if (!hasOtherBadTags) { + EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, status); } - System.out.println( - "TAG " + ((TagNameDefinition) event.getNewValue()).getDisplayName() + " event FROM " + ((TagNameDefinition) event.getOldValue()).getKnownStatus() + " TO " + ((TagNameDefinition) event.getNewValue()).getKnownStatus()); - EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, status); } } - // Now search for files List fileTags = Case.getCurrentCase().getSleuthkitCase().getContentTagsByTagName(tagName); for (ContentTag contentTag : fileTags) { + boolean hasOtherBadTags = false; if (status == TskData.FileKnown.UNKNOWN) { Content content = contentTag.getContent(); TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List tags = tagsManager.getContentTagsByContent(content); - if (!(tags.stream() - .map(tag -> tag.getName().getDisplayName()) - .filter(notableTags::contains) - .collect(Collectors.toList()) - .isEmpty())) { // There are more bad tags on the object - continue; + for (ContentTag t : tags) { + if (t.getName().equals(tagName)) { + continue; + } + if (notableTags.contains(t.getName().getDisplayName())) { + hasOtherBadTags = true; + break; + } } } - System.out.println("MAKING ARTIFACT"); - final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(contentTag.getContent(), - TskData.FileKnown.BAD, ""); - if (eamArtifact != null) { - EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, status); - System.out.println( - "TAG " + ((TagNameDefinition) event.getNewValue()).getDisplayName() + " event FROM " + ((TagNameDefinition) event.getOldValue()).getKnownStatus() + " TO " + ((TagNameDefinition) event.getNewValue()).getKnownStatus()); + if (!hasOtherBadTags) { + final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(contentTag.getContent(), + status, ""); + if (eamArtifact != null) { + EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, status); + } } } } catch (TskCoreException ex) { From 55efc419ab9050d154df9fc587d5b27c0918dc6a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Nov 2017 18:16:44 -0500 Subject: [PATCH 03/34] 3202 rename gui elements in TagOptionsPanel, change @messages --- .../casemodule/services/Bundle.properties | 8 +-- .../casemodule/services/TagOptionsPanel.form | 16 +++--- .../casemodule/services/TagOptionsPanel.java | 54 +++++++++++-------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 4cca7e78d6..95fd09a57b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -9,15 +9,9 @@ TagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name TagOptionsPanel.tagTypesListLabel.text=Tag Names: TagOptionsPanel.deleteTagNameButton.text=Delete Tag TagOptionsPanel.newTagNameButton.text=New Tag -TagOptionsPanel.editTagNameButton.text=Edit Tag TagNameDialog.descriptionLabel.text=Description: TagNameDialog.okButton.text=OK TagNameDialog.cancelButton.text=Cancel TagNameDialog.tagNameTextField.text= TagNameDialog.newTagNameLabel.text=Name: -TagNameDialog.notableCheckbox.text=Tag indicates item is notable. -TagOptionsPanel.isNotableLabel.text=Tag indicates item is notable: -TagOptionsPanel.notableYesOrNoLabel.text= -TagOptionsPanel.descriptionLabel.text=Tag Description: -TagOptionsPanel.jTextArea1.text=Create and manage tags, which can be applied to files and results in the case. Notable tags will cause items tagged with them to be flagged as notable when using a central repository. -TagOptionsPanel.ingestRunningWarningLabel.text=Cannot make changes to existing tags when ingest is running! +TagNameDialog.notableCheckbox.text=Tag indicates item is notable. \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form index 541bd90cda..2d763857be 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form @@ -91,7 +91,7 @@ - + @@ -100,7 +100,7 @@ - + @@ -113,11 +113,11 @@ - + - + @@ -137,7 +137,7 @@ - + @@ -223,14 +223,14 @@ - + - + @@ -243,7 +243,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index 02f3b925fb..c0be5bd9f4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -59,6 +59,16 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { customizeComponents(); } + @Messages({"TagOptionsPanel.panelDescriptionTextArea.text=Create and manage tags. " + + "Tags can be applied to files and results in the case. Notable tags will cause " + + "items tagged with them to be flagged as notable when using a central repository. " + + "Changing the status of a tag will only effect items in the current case.", + "TagOptionsPanel.ingestRunningWarningLabel.text=Cannot make changes to existing tags when ingest is running!", + "TagOptionsPanel.descriptionLabel.text=Tag Description:", + "TagOptionsPanel.notableYesOrNoLabel.text=", + "TagOptionsPanel.isNotableLabel.text=Tag indicates item is notable: ", + "TagOptionsPanel.editTagNameButton.text=Edit Tag"}) + private void customizeComponents() { tagNamesList.setModel(tagTypesListModel); tagNamesList.addListSelectionListener((ListSelectionEvent event) -> { @@ -92,13 +102,13 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { jSplitPane1 = new javax.swing.JSplitPane(); modifyTagTypesListPanel = new javax.swing.JPanel(); tagTypesListLabel = new javax.swing.JLabel(); - jScrollPane1 = new javax.swing.JScrollPane(); + TagNameScrollPane = new javax.swing.JScrollPane(); tagNamesList = new javax.swing.JList<>(); newTagNameButton = new javax.swing.JButton(); deleteTagNameButton = new javax.swing.JButton(); editTagNameButton = new javax.swing.JButton(); - jScrollPane3 = new javax.swing.JScrollPane(); - jTextArea1 = new javax.swing.JTextArea(); + panelDescriptionScrollPane = new javax.swing.JScrollPane(); + panelDescriptionTextArea = new javax.swing.JTextArea(); tagTypesAdditionalPanel = new javax.swing.JPanel(); descriptionLabel = new javax.swing.JLabel(); descriptionScrollPane = new javax.swing.JScrollPane(); @@ -118,7 +128,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { org.openide.awt.Mnemonics.setLocalizedText(tagTypesListLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.tagTypesListLabel.text")); // NOI18N tagNamesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - jScrollPane1.setViewportView(tagNamesList); + TagNameScrollPane.setViewportView(tagNamesList); newTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newTagNameButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.newTagNameButton.text")); // NOI18N @@ -153,16 +163,16 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { } }); - jTextArea1.setEditable(false); - jTextArea1.setBackground(new java.awt.Color(240, 240, 240)); - jTextArea1.setColumns(20); - jTextArea1.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N - jTextArea1.setLineWrap(true); - jTextArea1.setRows(3); - jTextArea1.setText(org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.jTextArea1.text")); // NOI18N - jTextArea1.setWrapStyleWord(true); - jTextArea1.setFocusable(false); - jScrollPane3.setViewportView(jTextArea1); + panelDescriptionTextArea.setEditable(false); + panelDescriptionTextArea.setBackground(new java.awt.Color(240, 240, 240)); + panelDescriptionTextArea.setColumns(20); + panelDescriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + panelDescriptionTextArea.setLineWrap(true); + panelDescriptionTextArea.setRows(3); + panelDescriptionTextArea.setText(org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.panelDescriptionTextArea.text")); // NOI18N + panelDescriptionTextArea.setWrapStyleWord(true); + panelDescriptionTextArea.setFocusable(false); + panelDescriptionScrollPane.setViewportView(panelDescriptionTextArea); javax.swing.GroupLayout modifyTagTypesListPanelLayout = new javax.swing.GroupLayout(modifyTagTypesListPanel); modifyTagTypesListPanel.setLayout(modifyTagTypesListPanelLayout); @@ -175,14 +185,14 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(TagNameScrollPane, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, modifyTagTypesListPanelLayout.createSequentialGroup() .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(editTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(deleteTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(panelDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); @@ -193,11 +203,11 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() .addGap(10, 10, 10) - .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(tagTypesListLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 355, Short.MAX_VALUE) + .addComponent(TagNameScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 343, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -299,7 +309,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { }// //GEN-END:initComponents @Messages({"TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists.", - "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name"}) + "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name"}) private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagNameButtonActionPerformed TagNameDialog dialog = new TagNameDialog(); @@ -357,6 +367,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { }//GEN-LAST:event_editTagNameButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane TagNameScrollPane; private javax.swing.JButton deleteTagNameButton; private javax.swing.JLabel descriptionLabel; private javax.swing.JScrollPane descriptionScrollPane; @@ -365,14 +376,13 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private javax.swing.JLabel ingestRunningWarningLabel; private javax.swing.JLabel isNotableLabel; private javax.swing.JPanel jPanel1; - private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; - private javax.swing.JScrollPane jScrollPane3; private javax.swing.JSplitPane jSplitPane1; - private javax.swing.JTextArea jTextArea1; private javax.swing.JPanel modifyTagTypesListPanel; private javax.swing.JButton newTagNameButton; private javax.swing.JLabel notableYesOrNoLabel; + private javax.swing.JScrollPane panelDescriptionScrollPane; + private javax.swing.JTextArea panelDescriptionTextArea; private javax.swing.JList tagNamesList; private javax.swing.JPanel tagTypesAdditionalPanel; private javax.swing.JLabel tagTypesListLabel; From 9b511c3c0558664d1942edf61469fdd1dbfb2b8b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 14 Nov 2017 18:18:16 -0500 Subject: [PATCH 04/34] 3202 make TagsPanelDescription large enough for text --- .../autopsy/casemodule/services/TagOptionsPanel.form | 8 ++++---- .../autopsy/casemodule/services/TagOptionsPanel.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form index 2d763857be..8654d04598 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form @@ -113,11 +113,11 @@ - - + + - - + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index c0be5bd9f4..299a06219e 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -203,11 +203,11 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() .addGap(10, 10, 10) - .addComponent(panelDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(tagTypesListLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(TagNameScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 343, Short.MAX_VALUE) + .addComponent(TagNameScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 338, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) From e5b81aa96ef8bcda7e59b5202e688a86bdbffd0d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 20 Nov 2017 10:30:39 -0500 Subject: [PATCH 05/34] 3202 make TagNameDefinition non public again --- .../sleuthkit/autopsy/casemodule/Case.java | 5 +-- .../services/TagNameDefinition.java | 8 ++-- .../casemodule/services/TagOptionsPanel.java | 45 ++----------------- .../eventlisteners/CaseEventListener.java | 14 +++--- 4 files changed, 16 insertions(+), 56 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 1cadd0b0b2..2dcc532a37 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -76,7 +76,6 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent; import org.sleuthkit.autopsy.casemodule.services.Services; -import org.sleuthkit.autopsy.casemodule.services.TagNameDefinition; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CategoryNode; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; @@ -1479,8 +1478,8 @@ public class Case { eventPublisher.publish(new ContentTagDeletedEvent(deletedTag)); } - public void notifyTagStatusChanged(TagNameDefinition oldTag, TagNameDefinition newTag) { - eventPublisher.publish(new AutopsyEvent(Events.TAG_STATUS_CHANGED.toString(), oldTag, newTag)); + public void notifyTagStatusChanged(String changedTagName) { + eventPublisher.publish(new AutopsyEvent(Events.TAG_STATUS_CHANGED.toString(), changedTagName, changedTagName)); } /** * Notifies case event subscribers that an artifact tag has been added. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index 9c81afcaf8..56b142bdb4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -40,7 +40,7 @@ import org.sleuthkit.datamodel.TskData; * A tag name definition consisting of a display name, description and color. */ @Immutable -public final class TagNameDefinition implements Comparable { +final class TagNameDefinition implements Comparable { private static final Logger LOGGER = Logger.getLogger(TagNameDefinition.class.getName()); @NbBundle.Messages({"TagNameDefinition.predefTagNames.bookmark.text=Bookmark", @@ -68,7 +68,7 @@ public final class TagNameDefinition implements Comparable { * @param color The color for the tag name. * @param status The status denoted by the tag name. */ - public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { + TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { this.displayName = displayName; this.description = description; this.color = color; @@ -84,7 +84,7 @@ public final class TagNameDefinition implements Comparable { * * @return The display name. */ - public String getDisplayName() { + String getDisplayName() { return displayName; } @@ -112,7 +112,7 @@ public final class TagNameDefinition implements Comparable { * * @return a value of TskData.FileKnown which is associated with this tag */ - public TskData.FileKnown getKnownStatus() { + TskData.FileKnown getKnownStatus() { return knownStatus; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index 3f8210ae22..712fa6480d 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -46,7 +46,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private final DefaultListModel tagTypesListModel; private Set tagTypes; private IngestJobEventPropertyChangeListener ingestJobEventsListener; - private Set updatedStatusTags; + private Set updatedStatusTags; /** * Creates new form TagOptionsPanel @@ -361,7 +361,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { updatePanel(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); if (originalTagName.getKnownStatus() != newTagType.getKnownStatus() && Case.isCaseOpen()) { - updatedStatusTags.add(new TagPair(originalTagName, newTagType)); + updatedStatusTags.add(newTagType.getDisplayName()); } } }//GEN-LAST:event_editTagNameButtonActionPerformed @@ -422,8 +422,8 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { } private void sendStatusChangedEvents() { - for (TagPair modifiedTag : updatedStatusTags) { - Case.getCurrentCase().notifyTagStatusChanged(modifiedTag.getOldValue(), modifiedTag.getNewValue()); + for (String modifiedTagDisplayName : updatedStatusTags) { + Case.getCurrentCase().notifyTagStatusChanged(modifiedTagDisplayName); } updatedStatusTags.clear(); } @@ -445,7 +445,6 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { boolean enableDelete = enableEdit && !TagNameDefinition.getStandardTagNames().contains(tagNamesList.getSelectedValue().getDisplayName()); deleteTagNameButton.setEnabled(enableDelete); if (isSelected) { - descriptionTextArea.setText(tagNamesList.getSelectedValue().getDescription()); if (tagNamesList.getSelectedValue().getKnownStatus() == TskData.FileKnown.BAD) { notableYesOrNoLabel.setText("Yes"); @@ -468,42 +467,6 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { super.finalize(); } - private class TagPair implements Comparable { - - private TagNameDefinition oldValue; - private TagNameDefinition newValue; - - private TagPair(TagNameDefinition oldV, TagNameDefinition newV) { - oldValue = oldV; - newValue = newV; - } - - private TagNameDefinition getOldValue() { - return oldValue; - } - - private TagNameDefinition getNewValue() { - return newValue; - } - - /** - * Compares this tag name definition with the specified tag name - * definition for order. - * - * @param other The tag name definition to which to compare this tag - * name definition. - * - * @return Negative integer, zero, or a positive integer to indicate - * that this tag name definition is less than, equal to, or - * greater than the specified tag name definition. - */ - @Override - public int compareTo(TagPair other) { - return this.getNewValue().compareTo(other.getNewValue()); - } - - } - /** * A property change listener that listens to ingest job events. */ diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 6ecc0edb4a..57d56fc8d2 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -33,7 +33,6 @@ import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent; -import org.sleuthkit.autopsy.casemodule.services.TagNameDefinition; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; @@ -314,17 +313,17 @@ final class CaseEventListener implements PropertyChangeListener { if (!EamDb.isEnabled()) { return; } - TskData.FileKnown status = ((TagNameDefinition) event.getNewValue()).getKnownStatus(); + String modifiedTagName = (String) event.getNewValue(); + List notableTags = TagsManager.getNotableTagDisplayNames(); + TskData.FileKnown status = notableTags.contains(modifiedTagName) ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN; /** * Set knownBad status for all files/artifacts in the given case * that are tagged with the given tag name. */ - System.out.println("TAG " + ((TagNameDefinition) event.getNewValue()).getDisplayName() + " event FROM " + ((TagNameDefinition) event.getOldValue()).getKnownStatus().toString() + " TO " + status.toString()); try { - TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(((TagNameDefinition) event.getNewValue()).getDisplayName()); + TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(((TagName) event.getNewValue()).getDisplayName()); // First find any matching artifacts List artifactTags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName); - List notableTags = TagsManager.getNotableTagDisplayNames(); for (BlackboardArtifactTag bbTag : artifactTags) { List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true); for (CorrelationAttribute eamArtifact : convertedArtifacts) { @@ -379,11 +378,10 @@ final class CaseEventListener implements PropertyChangeListener { } } } catch (TskCoreException ex) { - System.out.println("Cannot update "); + LOGGER.log(Level.SEVERE, "Cannot update known status in central repository"); //NON-NLS } catch (EamDbException ex) { - System.out.println("Cannot get CR"); + LOGGER.log(Level.SEVERE, "Cannot get central repository"); //NON-NLS } - } //TAG_STATUS_CHANGED } From de618cf8ddb678e2f34d256ef6eea862c9cce2a1 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 20 Nov 2017 12:46:38 -0500 Subject: [PATCH 06/34] 3201 fix casting error in CR case event listener --- .../centralrepository/eventlisteners/CaseEventListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 57d56fc8d2..fb01f48f2a 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -321,7 +321,7 @@ final class CaseEventListener implements PropertyChangeListener { * that are tagged with the given tag name. */ try { - TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(((TagName) event.getNewValue()).getDisplayName()); + TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get((String) event.getNewValue()); // First find any matching artifacts List artifactTags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName); for (BlackboardArtifactTag bbTag : artifactTags) { From 1f349579b010951e1bca9aa8dd25d35f2d31adbd Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 20 Nov 2017 13:00:50 -0500 Subject: [PATCH 07/34] 3202 remove unused arguement from TagStatusChangeTask, add comments --- .../eventlisteners/CaseEventListener.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index fb01f48f2a..ff4db6d8eb 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -99,7 +99,7 @@ final class CaseEventListener implements PropertyChangeListener { } break; case TAG_STATUS_CHANGED: { - jobProcessingExecutor.submit(new TagStatusChangeTask(dbManager, evt)); + jobProcessingExecutor.submit(new TagStatusChangeTask(evt)); } break; case CURRENT_CASE: { @@ -300,11 +300,9 @@ final class CaseEventListener implements PropertyChangeListener { private final class TagStatusChangeTask implements Runnable { - private final EamDb dbManager; private final PropertyChangeEvent event; - private TagStatusChangeTask(EamDb db, PropertyChangeEvent evt) { - dbManager = db; + private TagStatusChangeTask(PropertyChangeEvent evt) { event = evt; } @@ -328,6 +326,7 @@ final class CaseEventListener implements PropertyChangeListener { List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true); for (CorrelationAttribute eamArtifact : convertedArtifacts) { boolean hasOtherBadTags = false; + //if the new status of the tag is unknown UNKNOWN ensure we are not changing the status of BlackboardArtifact which still have other tags with a non-unknown status if (status == TskData.FileKnown.UNKNOWN) { Content content = bbTag.getContent(); if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) { @@ -337,9 +336,11 @@ final class CaseEventListener implements PropertyChangeListener { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); for (BlackboardArtifactTag t : tags) { + //avoid the possibility for threading issues if the tag whose status is currently changing is ever still in the tags manager with the old status if (t.getName().equals(tagName)) { continue; } + //if any other tags on this artifact are Notable in status then this artifact can not have its status changed if (notableTags.contains(t.getName().getDisplayName())) { hasOtherBadTags = true; break; @@ -355,14 +356,17 @@ final class CaseEventListener implements PropertyChangeListener { List fileTags = Case.getCurrentCase().getSleuthkitCase().getContentTagsByTagName(tagName); for (ContentTag contentTag : fileTags) { boolean hasOtherBadTags = false; + //if the new status of the tag is unknown UNKNOWN ensure we are not changing the status of files which still have other tags with a Notable status if (status == TskData.FileKnown.UNKNOWN) { Content content = contentTag.getContent(); TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List tags = tagsManager.getContentTagsByContent(content); for (ContentTag t : tags) { + //avoid the possibility for threading issues if the tag whose status is currently changing is ever still in the tags manager with the old status if (t.getName().equals(tagName)) { continue; } + //if any other tags on this file are Notable in status then this file can not have its status changed if (notableTags.contains(t.getName().getDisplayName())) { hasOtherBadTags = true; break; From da82b9457b0dfc5dd1aa06599badc18aa047ed42 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 20 Nov 2017 14:11:51 -0500 Subject: [PATCH 08/34] 3202 fix logging for possible exceptions in case event listener --- .../centralrepository/eventlisteners/CaseEventListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index ff4db6d8eb..cc6dbaf142 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -319,7 +319,7 @@ final class CaseEventListener implements PropertyChangeListener { * that are tagged with the given tag name. */ try { - TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get((String) event.getNewValue()); + TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName); // First find any matching artifacts List artifactTags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName); for (BlackboardArtifactTag bbTag : artifactTags) { @@ -382,9 +382,9 @@ final class CaseEventListener implements PropertyChangeListener { } } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Cannot update known status in central repository"); //NON-NLS + LOGGER.log(Level.SEVERE, "Cannot update known status in central repository for tag: " + modifiedTagName, ex); //NON-NLS } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Cannot get central repository"); //NON-NLS + LOGGER.log(Level.SEVERE, "Cannot get central repository for tag: " + modifiedTagName, ex); //NON-NLS } } //TAG_STATUS_CHANGED } From dbe357c6444522f0d8b472acaa634dcf5589a75e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 21 Nov 2017 10:58:41 -0500 Subject: [PATCH 09/34] Partial implementation. --- .../autoingest/AutoIngestJobNodeData.java | 37 +++++++++++++++++-- .../autoingest/AutoIngestManager.java | 9 +++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java index e2b267fded..e3ecf177e1 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java @@ -31,7 +31,7 @@ import javax.lang.model.type.TypeKind; */ final class AutoIngestJobNodeData { - private static final int CURRENT_VERSION = 1; + private static final int CURRENT_VERSION = 2; private static final int DEFAULT_PRIORITY = 0; /* @@ -47,7 +47,7 @@ final class AutoIngestJobNodeData { * data. This avoids the need to continuously enlarge the buffer. Once the * buffer has all the necessary data, it will be resized as appropriate. */ - private static final int MAX_POSSIBLE_NODE_DATA_SIZE = 131629; + private static final int MAX_POSSIBLE_NODE_DATA_SIZE = 131637; /* * Version 0 fields. @@ -73,6 +73,11 @@ final class AutoIngestJobNodeData { private long processingStageStartDate; private String processingStageDetailsDescription; // 'byte' length used in byte array private long processingStageDetailsStartDate; + + /* + * Version 2 fields. + */ + private long dataSourceSize; /** * Gets the current version of the auto ingest job coordination service node @@ -109,6 +114,7 @@ final class AutoIngestJobNodeData { setProcessingStage(job.getProcessingStage()); setProcessingStageStartDate(job.getProcessingStageStartDate()); setProcessingStageDetails(job.getProcessingStageDetails()); + //DLG: } /** @@ -143,6 +149,7 @@ final class AutoIngestJobNodeData { this.processingStageStartDate = 0L; this.processingStageDetailsDescription = ""; this.processingStageDetailsStartDate = 0L; + this.dataSourceSize = 0L; /* * Get fields from node data. @@ -177,6 +184,10 @@ final class AutoIngestJobNodeData { this.processingStageDetailsDescription = getStringFromBuffer(buffer, TypeKind.BYTE); this.processingStageDetailsStartDate = buffer.getLong(); this.processingHostName = getStringFromBuffer(buffer, TypeKind.SHORT); + + if (this.version >= 2) { + this.dataSourceSize = buffer.getLong(); + } } } catch (BufferUnderflowException ex) { @@ -498,6 +509,22 @@ final class AutoIngestJobNodeData { void setProcessingHostName(String processingHost) { this.processingHostName = processingHost; } + + /** + * DLG: + */ + long getDataSourceSize() { + return this.dataSourceSize; + } + + /** + * DLG: + * + * @param DLG: + */ + void setDataSourceSize(long dataSourceSize) { + this.dataSourceSize = dataSourceSize; + } /** * Gets the node data as a byte array that can be sent to the coordination @@ -515,7 +542,7 @@ final class AutoIngestJobNodeData { buffer.putLong(this.completedDate); buffer.putInt(this.errorsOccurred ? 1 : 0); - if (this.version > 0) { + if (this.version >= 1) { // Write version buffer.putInt(this.version); @@ -531,6 +558,10 @@ final class AutoIngestJobNodeData { putStringIntoBuffer(this.processingStageDetailsDescription, buffer, TypeKind.BYTE); buffer.putLong(this.processingStageDetailsStartDate); putStringIntoBuffer(processingHostName, buffer, TypeKind.SHORT); + + if (this.version >= 2) { + buffer.putLong(this.dataSourceSize); + } } // Prepare the array diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 35b563b961..d537c76146 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -2263,6 +2263,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen return; } + collectMetrics(/*DLG:*/); exportFiles(dataSource); } @@ -2543,6 +2544,14 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen currentJob.setIngestJob(null); } } + + /* + * DLG: + */ + private void collectMetrics(/*DLG:*/) { + + AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(currentJob); + } /** * Exports any files from the data source for the current job that From 5f8b860545e6d8e77e0e04a44ba7d9b9ff825044 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 22 Nov 2017 01:05:08 -0500 Subject: [PATCH 10/34] 'collectMetrics()' method implemented. --- .../autoingest/AutoIngestManager.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index d537c76146..199cb8a8db 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -98,6 +98,9 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobStartResult; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleError; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.DataSource; +import org.sleuthkit.datamodel.SleuthkitCase; /** * An auto ingest manager is responsible for processing auto ingest jobs defined @@ -2263,7 +2266,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen return; } - collectMetrics(/*DLG:*/); + collectMetrics(caseForJob.getSleuthkitCase(), dataSource); exportFiles(dataSource); } @@ -2548,9 +2551,18 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen /* * DLG: */ - private void collectMetrics(/*DLG:*/) { - + private void collectMetrics(SleuthkitCase caseDb, AutoIngestDataSource dataSource) throws CoordinationServiceException, InterruptedException { + List contentList = dataSource.getContent(); + long dataSourceSize = 0; + for (Content content : contentList) { + // DLG: Why multiply Content objects? + // DLG: What to do if more than one? + dataSourceSize = ((DataSource)content).getContentSize(caseDb); + } AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(currentJob); + nodeData.setDataSourceSize(dataSourceSize); + String manifestNodePath = currentJob.getManifest().getFilePath().toString(); + coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, nodeData.toArray()); } /** From 0e21b699930052940d0a6f28b54882c94536091d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 22 Nov 2017 12:02:46 -0500 Subject: [PATCH 11/34] 3203-add (Notable) to tag context menus --- .../autopsy/actions/AddTagAction.java | 17 ++-- .../autopsy/actions/Bundle.properties | 6 +- .../autopsy/actions/Bundle_ja.properties | 4 +- ...DeleteFileBlackboardArtifactTagAction.java | 58 +++++------ .../actions/DeleteFileContentTagAction.java | 4 +- .../actions/GetTagNameAndCommentDialog.form | 11 +-- .../actions/GetTagNameAndCommentDialog.java | 95 +++++++++---------- .../autopsy/actions/GetTagNameDialog.form | 64 +++++++++++-- .../autopsy/actions/GetTagNameDialog.java | 80 ++++++++++++---- .../casemodule/services/TagNameDialog.form | 2 +- .../casemodule/services/TagNameDialog.java | 2 +- .../casemodule/services/TagsManager.java | 5 + .../imagegallery/actions/AddTagAction.java | 30 +++--- .../imagegallery/actions/DeleteTagAction.java | 58 ++++++----- 14 files changed, 270 insertions(+), 166 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index f665aeb7d5..95b68b87d6 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,12 +26,14 @@ import javax.swing.AbstractAction; import javax.swing.JMenu; import javax.swing.JMenuItem; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; 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; +import org.sleuthkit.datamodel.TskData; /** * An abstract base class for Actions that allow users to tag SleuthKit data @@ -107,7 +109,8 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { if (null != tagNamesMap && !tagNamesMap.isEmpty()) { for (Map.Entry entry : tagNamesMap.entrySet()) { String tagDisplayName = entry.getKey(); - JMenuItem tagNameItem = new JMenuItem(tagDisplayName); + String notableString = entry.getValue().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); // for the bookmark tag name only, added shortcut label if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) { tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT); @@ -122,7 +125,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags")); empty.setEnabled(false); quickTagMenu.add(empty); - } + } quickTagMenu.addSeparator(); @@ -155,10 +158,10 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { /** * Method to add to the action listener for each menu item. Allows a tag * display name to be added to the menu with an action listener without - * having to instantiate a TagName object for it. - * When the method is called, the TagName object is created here if it - * doesn't already exist. - * + * having to instantiate a TagName object for it. When the method is + * called, the TagName object is created here if it doesn't already + * exist. + * * @param tagDisplayName display name for the tag name * @param tagName TagName object associated with the tag name, * may be null diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties index 28d4e4006a..01d0d21b47 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -4,7 +4,7 @@ GetTagNameDialog.okButton.text=OK GetTagNameDialog.preexistingLabel.text=Pre-existing Tag Names: GetTagNameDialog.newTagPanel.border.title=New Tag GetTagNameDialog.tagNameLabel.text=Tag Name: -GetTagNameAndCommentDialog.newTagButton.text=New Tag Name +GetTagNameAndCommentDialog.newTagButton.text=New Tag GetTagNameAndCommentDialog.okButton.text=OK GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank GetTagNameAndCommentDialog.commentText.text= @@ -12,7 +12,6 @@ GetTagNameAndCommentDialog.commentLabel.text=Comment: # 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: AddTagAction.bookmarkFile=Bookmark file AddTagAction.quickTag=Quick Tag @@ -45,3 +44,6 @@ ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot OpenPythonModulesFolderAction.actionName.text=Python Plugins OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0} CTL_OpenPythonModulesFolderAction=Python Plugins +GetTagNameDialog.descriptionLabel.text=Description: +GetTagNameDialog.notableCheckbox.text=Tag indicates item is notable. +GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties index 195d12c695..d6f865ecf0 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties @@ -8,7 +8,6 @@ GetTagNameAndCommentDialog.okButton.text=OK GetTagNameAndCommentDialog.commentText.toolTipText=\u30bf\u30b0\u306e\u30aa\u30d7\u30b7\u30e7\u30ca\u30eb\u306e\u30b3\u30e1\u30f3\u30c8\u3092\u5165\u529b\u307e\u305f\u306f\u7a7a\u6b04\u306b\u3057\u3066\u304f\u3060\u3055\u3044 GetTagNameAndCommentDialog.commentLabel.text=\u30b3\u30e1\u30f3\u30c8\uff1a GetTagNameAndCommentDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb -GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4f7f\u7528\u3059\u308b\u30bf\u30b0\u3092\u9078\u629e GetTagNameAndCommentDialog.tagLabel.text=\u30bf\u30b0\uff1a AddBlackboardArtifactTagAction.singularTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0 AddBlackboardArtifactTagAction.pluralTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0 @@ -48,4 +47,5 @@ CTL_OpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c OpenOutputFolder.error1=\u6b21\u306e\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0} OpenOutputFolder.noCaseOpen=\u30aa\u30fc\u30d7\u30f3\u30b1\u30fc\u30b9\u304c\u306a\u3044\u306e\u3067\u3001\u4f5c\u696d\u4e2d\u306e\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u3042\u308a\u307e\u305b\u3093\u3002 GetTagNameDialog.illegalChars.msg=\u4f7f\u7528\u3067\u304d\u306a\u3044\u6587\u5b57\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3059\u3002\n\u6b21\u306e\u6587\u5b57\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093\uff1a\\ \: * ? " < > | -OpenOutputFolder.CouldNotOpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u304c\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f \ No newline at end of file +OpenOutputFolder.CouldNotOpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u304c\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f +GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4f7f\u7528\u3059\u308b\u30bf\u30b0\u3092\u9078\u629e diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java index d9fd5d364f..86696b0c63 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2017 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -43,6 +43,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** * Instances of this Action allow users to delete tags applied to blackboard @@ -52,7 +53,7 @@ import org.sleuthkit.datamodel.TskCoreException; "DeleteFileBlackboardArtifactTagAction.deleteTag=Remove Result Tag" }) public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implements Presenter.Popup { - + private static final Logger LOGGER = Logger.getLogger(DeleteFileBlackboardArtifactTagAction.class.getName()); private static final long serialVersionUID = 1L; @@ -89,27 +90,27 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem } @NbBundle.Messages({"# {0} - artifactID", - "DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}."}) + "DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}."}) protected void deleteTag(TagName tagName, BlackboardArtifactTag artifactTag, long artifactId) { new SwingWorker() { @Override protected Void doInBackground() throws Exception { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - + // Pull the from the global context to avoid unnecessary calls // to the database. - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); AbstractFile file = selectedFilesList.iterator().next(); - + try { LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS tagsManager.deleteBlackboardArtifactTag(artifactTag); } catch (TskCoreException tskCoreException) { LOGGER.log(Level.SEVERE, "Error untagging artifact", tskCoreException); //NON-NLS - Platform.runLater(() -> - new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show() + Platform.runLater(() + -> new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show() ); } return null; @@ -133,21 +134,21 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem * comment. */ @NbBundle.Messages({"# {0} - artifactID", - "DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}."}) + "DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}."}) private class TagMenu extends JMenu { private static final long serialVersionUID = 1L; TagMenu() { super(getActionDisplayName()); - - final Collection selectedBlackboardArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - - if(!selectedBlackboardArtifactsList.isEmpty()) { - BlackboardArtifact artifact = - selectedBlackboardArtifactsList.iterator().next(); - + + final Collection selectedBlackboardArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + + if (!selectedBlackboardArtifactsList.isEmpty()) { + BlackboardArtifact artifact + = selectedBlackboardArtifactsList.iterator().next(); + // Get the current set of tag names. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); @@ -163,17 +164,18 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem // a tag with the associated tag name. if (null != tagNamesMap && !tagNamesMap.isEmpty()) { try { - List existingTagsList = - Case.getCurrentCase().getServices().getTagsManager() - .getBlackboardArtifactTagsByArtifact(artifact); + List existingTagsList + = Case.getCurrentCase().getServices().getTagsManager() + .getBlackboardArtifactTagsByArtifact(artifact); for (Map.Entry entry : tagNamesMap.entrySet()) { String tagDisplayName = entry.getKey(); TagName tagName = entry.getValue(); - for(BlackboardArtifactTag artifactTag : existingTagsList) { - if(tagDisplayName.equals(artifactTag.getName().getDisplayName())) { - JMenuItem tagNameItem = new JMenuItem(tagDisplayName); + for (BlackboardArtifactTag artifactTag : existingTagsList) { + if (tagDisplayName.equals(artifactTag.getName().getDisplayName())) { + String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); tagNameItem.addActionListener((ActionEvent e) -> { deleteTag(tagName, artifactTag, artifact.getArtifactID()); }); @@ -187,7 +189,7 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem } } - if(getItemCount() == 0) { + if (getItemCount() == 0) { setEnabled(false); } } diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java index e49e0f9170..5c8d4abb74 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java @@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** * Instances of this Action allow users to delete tags applied to content. @@ -169,7 +170,8 @@ public class DeleteFileContentTagAction extends AbstractAction implements Presen TagName tagName = entry.getValue(); for(ContentTag contentTag : existingTagsList) { if(tagDisplayName.equals(contentTag.getName().getDisplayName())) { - JMenuItem tagNameItem = new JMenuItem(tagDisplayName); + String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); tagNameItem.addActionListener((ActionEvent e) -> { deleteTag(tagName, contentTag, file.getId()); }); diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form index 17a9738dbd..57c43e964b 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form @@ -28,7 +28,7 @@ - + @@ -39,11 +39,10 @@ - + - + - @@ -108,8 +107,8 @@ - - + + diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 647d851341..e01a887949 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2011-2016 Basis Technology Corp. + * + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * 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. @@ -18,17 +18,20 @@ */ package org.sleuthkit.autopsy.actions; +import java.awt.Component; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; -import java.util.Map; -import java.util.TreeMap; import java.util.logging.Level; +import java.util.HashSet; +import java.util.Set; import javax.swing.AbstractAction; import javax.swing.ActionMap; +import javax.swing.DefaultListCellRenderer; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JDialog; +import javax.swing.JList; import javax.swing.KeyStroke; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; @@ -37,15 +40,14 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; public class GetTagNameAndCommentDialog extends JDialog { private static final long serialVersionUID = 1L; - private static final String NO_TAG_NAMES_MESSAGE = NbBundle.getMessage(GetTagNameAndCommentDialog.class, - "GetTagNameAndCommentDialog.noTags"); - private final Map tagNamesMap = new TreeMap<>(); + private final Set tagNamesSet = new HashSet<>(); private TagNameAndComment tagNameAndComment = null; - + public static class TagNameAndComment { private final TagName tagName; @@ -68,7 +70,7 @@ public class GetTagNameAndCommentDialog extends JDialog { /** * Show the Tag Name and Comment Dialog and return the TagNameAndContent * chosen by the user. The dialog will be centered with the main autopsy - * window as its owner. + * window as its owner. * * @return a TagNameAndComment instance containing the TagName selected by * the user and the entered comment, or null if the user canceled @@ -102,21 +104,34 @@ public class GetTagNameAndCommentDialog extends JDialog { ModalityType.APPLICATION_MODAL); } + private void display() { initComponents(); - + tagCombo.setRenderer(new DefaultListCellRenderer() { + private static final long serialVersionUID = 1L; + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + String status = ((TagName) value).getKnownStatus() == TskData.FileKnown.BAD ?TagsManager.getNotableTagLabel() : ""; + String newValue = ((TagName) value).getDisplayName() + status; + return super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus); + } + }); // Set up the dialog to close when Esc is pressed. String cancelName = NbBundle.getMessage(this.getClass(), "GetTagNameAndCommentDialog.cancelName"); 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() { private static final long serialVersionUID = 1L; + @Override public void actionPerformed(ActionEvent e) { dispose(); } - }); + } + ); // 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. @@ -124,23 +139,22 @@ public class GetTagNameAndCommentDialog extends JDialog { // not exist in the database). TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); try { - tagNamesMap.putAll(tagsManager.getDisplayNamesToTagNamesMap()); + tagNamesSet.addAll(tagsManager.getAllTagNames()); + } catch (TskCoreException ex) { - Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS + Logger.getLogger(GetTagNameAndCommentDialog.class + .getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } - if (null != tagNamesMap && tagNamesMap.isEmpty()) { - tagCombo.addItem(NO_TAG_NAMES_MESSAGE); - } else { - for (String tagDisplayName : tagNamesMap.keySet()) { - tagCombo.addItem(tagDisplayName); - } + for (TagName tag : tagNamesSet) { + + tagCombo.addItem(tag); } // Center and show the dialog box. this.setLocationRelativeTo(this.getOwner()); - setVisible(true); + setVisible(true); } - + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -152,7 +166,7 @@ public class GetTagNameAndCommentDialog extends JDialog { okButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton(); - tagCombo = new javax.swing.JComboBox(); + tagCombo = new javax.swing.JComboBox(); tagLabel = new javax.swing.JLabel(); commentLabel = new javax.swing.JLabel(); commentText = new javax.swing.JTextField(); @@ -203,7 +217,7 @@ public class GetTagNameAndCommentDialog extends JDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(newTagButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 48, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 165, Short.MAX_VALUE) .addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(cancelButton)) @@ -212,10 +226,9 @@ public class GetTagNameAndCommentDialog extends JDialog { .addComponent(commentLabel) .addComponent(tagLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(commentText) - .addComponent(tagCombo, 0, 214, Short.MAX_VALUE)) - .addGap(0, 0, Short.MAX_VALUE))) + .addComponent(tagCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) .addContainerGap()) ); @@ -246,21 +259,7 @@ public class GetTagNameAndCommentDialog extends JDialog { }// //GEN-END:initComponents private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - String tagDisplayName = (String) tagCombo.getSelectedItem(); - TagName tagNameFromCombo = tagNamesMap.get(tagDisplayName); - if (tagNameFromCombo == null) { - try { - tagNameFromCombo = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - try { - tagNameFromCombo = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(tagDisplayName); - } catch (TskCoreException ex1) { - Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database but an error occurred in retrieving it.", ex1); //NON-NLS - } - } catch (TskCoreException ex) { - Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS - } - } + TagName tagNameFromCombo = (TagName) tagCombo.getSelectedItem(); tagNameAndComment = new TagNameAndComment(tagNameFromCombo, commentText.getText()); dispose(); }//GEN-LAST:event_okButtonActionPerformed @@ -278,9 +277,9 @@ public class GetTagNameAndCommentDialog extends JDialog { private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed TagName newTagName = GetTagNameDialog.doDialog(this); if (newTagName != null) { - tagNamesMap.put(newTagName.getDisplayName(), newTagName); - tagCombo.addItem(newTagName.getDisplayName()); - tagCombo.setSelectedItem(newTagName.getDisplayName()); + tagNamesSet.add(newTagName); + tagCombo.addItem(newTagName); + tagCombo.setSelectedItem(newTagName); } }//GEN-LAST:event_newTagButtonActionPerformed @@ -290,7 +289,7 @@ public class GetTagNameAndCommentDialog extends JDialog { private javax.swing.JTextField commentText; private javax.swing.JButton newTagButton; private javax.swing.JButton okButton; - private javax.swing.JComboBox tagCombo; + private javax.swing.JComboBox tagCombo; private javax.swing.JLabel tagLabel; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form index a281ea606e..bf17a398a7 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form @@ -142,11 +142,20 @@ - + - - - + + + + + + + + + + + + @@ -154,12 +163,17 @@ + + - - - - - + + + + + + + + @@ -182,6 +196,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 4e5720a0fc..1619c95fed 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2011-2016 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. @@ -42,6 +42,7 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; public class GetTagNameDialog extends JDialog { @@ -79,7 +80,7 @@ public class GetTagNameDialog extends JDialog { } private GetTagNameDialog(Window owner) { - super(owner, + super(owner, NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.createTag"), ModalityType.APPLICATION_MODAL); } @@ -95,7 +96,7 @@ public class GetTagNameDialog extends JDialog { ActionMap actionMap = getRootPane().getActionMap(); actionMap.put(cancelName, new AbstractAction() { private static final long serialVersionUID = 1L; - + @Override public void actionPerformed(ActionEvent e) { cancelButtonActionPerformed(e); @@ -120,9 +121,9 @@ public class GetTagNameDialog extends JDialog { // Center and show the dialog box. this.setLocationRelativeTo(this.getOwner()); - setVisible(true); + setVisible(true); } - + private class TagsTableModel extends AbstractTableModel { private static final long serialVersionUID = 1L; @@ -172,6 +173,10 @@ public class GetTagNameDialog extends JDialog { newTagPanel = new javax.swing.JPanel(); tagNameLabel = new javax.swing.JLabel(); tagNameField = new javax.swing.JTextField(); + descriptionLabel = new javax.swing.JLabel(); + descriptionScrollPane = new javax.swing.JScrollPane(); + descriptionTextArea = new javax.swing.JTextArea(); + notableCheckbox = new javax.swing.JCheckBox(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); addKeyListener(new java.awt.event.KeyAdapter() { @@ -223,25 +228,46 @@ public class GetTagNameDialog extends JDialog { } }); + org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.descriptionLabel.text")); // NOI18N + + descriptionTextArea.setColumns(20); + descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + descriptionTextArea.setRows(3); + descriptionScrollPane.setViewportView(descriptionTextArea); + + org.openide.awt.Mnemonics.setLocalizedText(notableCheckbox, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.notableCheckbox.text")); // NOI18N + javax.swing.GroupLayout newTagPanelLayout = new javax.swing.GroupLayout(newTagPanel); newTagPanel.setLayout(newTagPanelLayout); newTagPanelLayout.setHorizontalGroup( newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(newTagPanelLayout.createSequentialGroup() .addContainerGap() - .addComponent(tagNameLabel) - .addGap(36, 36, 36) - .addComponent(tagNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 235, Short.MAX_VALUE) + .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(descriptionScrollPane, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(tagNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 323, Short.MAX_VALUE) + .addGroup(newTagPanelLayout.createSequentialGroup() + .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(notableCheckbox) + .addComponent(descriptionLabel) + .addComponent(tagNameLabel)) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); newTagPanelLayout.setVerticalGroup( newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(newTagPanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(tagNameLabel) - .addComponent(tagNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(164, Short.MAX_VALUE)) + .addGap(6, 6, 6) + .addComponent(tagNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tagNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(descriptionLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(descriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 57, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(notableCheckbox) + .addContainerGap(31, Short.MAX_VALUE)) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); @@ -288,8 +314,12 @@ public class GetTagNameDialog extends JDialog { dispose(); }//GEN-LAST:event_cancelButtonActionPerformed + @NbBundle.Messages({"GetTagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists.", + "GetTagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name"}) private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed String tagDisplayName = tagNameField.getText(); + String userTagDescription = descriptionTextArea.getText(); + TskData.FileKnown status = notableCheckbox.isSelected() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN; if (tagDisplayName.isEmpty()) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), @@ -301,11 +331,18 @@ public class GetTagNameDialog extends JDialog { NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalChars.msg"), NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"), JOptionPane.ERROR_MESSAGE); + } else if (userTagDescription.contains(",") + || userTagDescription.contains(";")) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalChars.msg"), + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"), + JOptionPane.ERROR_MESSAGE); } else { tagName = tagNamesMap.get(tagDisplayName); + if (tagName == null) { try { - tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName); + tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName, userTagDescription, TagName.HTML_COLOR.NONE, status); dispose(); } catch (TskCoreException ex) { Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS @@ -331,7 +368,10 @@ public class GetTagNameDialog extends JDialog { } } } else { - dispose(); + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameAlreadyExists.message"), + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameAlreadyExists.title"), + JOptionPane.INFORMATION_MESSAGE); } } }//GEN-LAST:event_okButtonActionPerformed @@ -350,8 +390,12 @@ public class GetTagNameDialog extends JDialog { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton cancelButton; + private javax.swing.JLabel descriptionLabel; + private javax.swing.JScrollPane descriptionScrollPane; + private javax.swing.JTextArea descriptionTextArea; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JPanel newTagPanel; + private javax.swing.JCheckBox notableCheckbox; private javax.swing.JButton okButton; private javax.swing.JLabel preexistingLabel; private javax.swing.JTextField tagNameField; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.form index e8162e6b3b..a88e25eb55 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.form @@ -117,7 +117,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java index 9b8584d293..0d0f07aa89 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java @@ -231,7 +231,7 @@ final class TagNameDialog extends javax.swing.JDialog { descriptionTextArea.setColumns(20); descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N - descriptionTextArea.setRows(5); + descriptionTextArea.setRows(3); descriptionScrollPane.setViewportView(descriptionTextArea); org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.descriptionLabel.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index e67f8a3484..b28769a50a 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -69,6 +70,10 @@ public class TagsManager implements Closeable { || tagDisplayName.contains(";")); } + @NbBundle.Messages({"TagsManager.notableTagEnding.text= (Notable)"}) + public static String getNotableTagLabel(){ + return Bundle.TagsManager_notableTagEnding_text(); + } /** * Gets the set of display names of the currently available tag types. This diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index e116ff171c..cd40efdb55 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2013-16 Basis Technology Corp. + * + * Copyright 2013-2017 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -36,10 +36,12 @@ import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.controlsfx.control.action.ActionUtils; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; @@ -48,6 +50,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskCoreException; /** @@ -67,7 +70,8 @@ public class AddTagAction extends Action { this.selectedFileIDs = selectedFileIDs; this.tagName = tagName; setGraphic(controller.getTagsManager().getGraphic(tagName)); - setText(tagName.getDisplayName()); + String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + setText(tagName.getDisplayName() + notableString); setEventHandler(actionEvent -> addTagWithComment("")); } @@ -78,7 +82,7 @@ public class AddTagAction extends Action { private void addTagWithComment(String comment) { addTagsToFiles(tagName, comment, selectedFileIDs); } - + @NbBundle.Messages({"# {0} - fileID", "AddDrawableTagAction.addTagsToFiles.alert=Unable to tag file {0}."}) private void addTagsToFiles(TagName tagName, String comment, Set selectedFiles) { @@ -108,8 +112,8 @@ public class AddTagAction extends Action { } catch (TskCoreException tskCoreException) { LOGGER.log(Level.SEVERE, "Error tagging file", tskCoreException); //NON-NLS - Platform.runLater(() -> - new Alert(Alert.AlertType.ERROR, Bundle.AddDrawableTagAction_addTagsToFiles_alert(fileID)).show() + Platform.runLater(() + -> new Alert(Alert.AlertType.ERROR, Bundle.AddDrawableTagAction_addTagsToFiles_alert(fileID)).show() ); break; } @@ -172,8 +176,8 @@ public class AddTagAction extends Action { * or select a tag name and adds a tag with the resulting name. */ MenuItem newTagMenuItem = new MenuItem(Bundle.AddTagAction_menuItem_newTag()); - newTagMenuItem.setOnAction(actionEvent -> - SwingUtilities.invokeLater(() -> { + newTagMenuItem.setOnAction(actionEvent + -> SwingUtilities.invokeLater(() -> { TagName tagName = GetTagNameDialog.doDialog(getIGWindow()); if (tagName != null) { new AddTagAction(controller, tagName, selectedFileIDs).handle(actionEvent); @@ -188,8 +192,8 @@ public class AddTagAction extends Action { * name. */ MenuItem tagAndCommentItem = new MenuItem(Bundle.AddTagAction_menuItem_tagAndComment()); - tagAndCommentItem.setOnAction(actionEvent -> - SwingUtilities.invokeLater(() -> { + tagAndCommentItem.setOnAction(actionEvent + -> SwingUtilities.invokeLater(() -> { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(getIGWindow()); if (null != tagNameAndComment) { new AddTagAction(controller, tagNameAndComment.getTagName(), selectedFileIDs).addTagWithComment(tagNameAndComment.getComment()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java index 53a033a2c9..a21d163fdc 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2017 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.awt.Window; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; @@ -30,24 +29,22 @@ import javafx.scene.control.Alert; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; import javafx.scene.image.ImageView; -import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.controlsfx.control.action.ActionUtils; import org.openide.util.NbBundle; import org.openide.util.Utilities; -import org.openide.windows.TopComponent; -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.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** * Instances of this Action allow users to remove tags from content. @@ -68,7 +65,8 @@ public class DeleteTagAction extends Action { this.tagName = tagName; this.contentTag = contentTag; setGraphic(controller.getTagsManager().getGraphic(tagName)); - setText(tagName.getDisplayName()); + String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + setText(tagName.getDisplayName() + notableString); setEventHandler(actionEvent -> deleteTag()); } @@ -84,20 +82,20 @@ public class DeleteTagAction extends Action { @Override protected Void doInBackground() throws Exception { DrawableTagsManager tagsManager = controller.getTagsManager(); - + // Pull the from the global context to avoid unnecessary calls // to the database. - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); AbstractFile file = selectedFilesList.iterator().next(); - + try { LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS tagsManager.deleteContentTag(contentTag); } catch (TskCoreException tskCoreException) { LOGGER.log(Level.SEVERE, "Error untagging file", tskCoreException); //NON-NLS - Platform.runLater(() -> - new Alert(Alert.AlertType.ERROR, Bundle.DeleteDrawableTagAction_deleteTag_alert(fileId)).show() + Platform.runLater(() + -> new Alert(Alert.AlertType.ERROR, Bundle.DeleteDrawableTagAction_deleteTag_alert(fileId)).show() ); } return null; @@ -121,25 +119,25 @@ public class DeleteTagAction extends Action { TagMenu(ImageGalleryController controller) { setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon())); setText(Bundle.DeleteDrawableTagAction_displayName()); - + // For this menu, we shouldn't have more than one file selected. // Therefore, we will simply grab the first file and work with that. - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); AbstractFile file = selectedFilesList.iterator().next(); - - try { - List existingTagsList = - Case.getCurrentCase().getServices().getTagsManager() - .getContentTagsByContent(file); - Collection tagNamesList = - controller.getTagsManager().getNonCategoryTagNames(); + try { + List existingTagsList + = Case.getCurrentCase().getServices().getTagsManager() + .getContentTagsByContent(file); + + Collection tagNamesList + = controller.getTagsManager().getNonCategoryTagNames(); Iterator tagNameIterator = tagNamesList.iterator(); - for(int i=0; tagNameIterator.hasNext(); i++) { + for (int i = 0; tagNameIterator.hasNext(); i++) { TagName tagName = tagNameIterator.next(); - for(ContentTag contentTag : existingTagsList) { - if(contentTag.getName().getId() == tagName.getId()) { + for (ContentTag contentTag : existingTagsList) { + if (contentTag.getName().getId() == tagName.getId()) { DeleteTagAction deleteDrawableTagAction = new DeleteTagAction(controller, tagName, contentTag, file.getId()); MenuItem tagNameItem = ActionUtils.createMenuItem(deleteDrawableTagAction); getItems().add(tagNameItem); @@ -151,7 +149,7 @@ public class DeleteTagAction extends Action { .log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS } - if(getItems().isEmpty()) { + if (getItems().isEmpty()) { setDisable(true); } } From 9d31a784baf11aa781ab9b7bb464f6170c9f8205 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 22 Nov 2017 12:13:23 -0500 Subject: [PATCH 12/34] 3203 add check for comma or semicolon in tag description --- .../autopsy/actions/GetTagNameDialog.java | 8 ++-- .../casemodule/services/TagNameDialog.java | 47 ++++++++++++------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 1619c95fed..ec282dfa1f 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -315,7 +315,9 @@ public class GetTagNameDialog extends JDialog { }//GEN-LAST:event_cancelButtonActionPerformed @NbBundle.Messages({"GetTagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists.", - "GetTagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name"}) + "GetTagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name", + "GetTagNameDialog.tagDescriptionIllegalCharacters.message=Tag descriptions may not contain commas (,) or semicolons (;)", + "GetTagNameDialog.tagDescriptionIllegalCharacters.title=Invalid character in tag description"}) private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed String tagDisplayName = tagNameField.getText(); String userTagDescription = descriptionTextArea.getText(); @@ -334,8 +336,8 @@ public class GetTagNameDialog extends JDialog { } else if (userTagDescription.contains(",") || userTagDescription.contains(";")) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalChars.msg"), - NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"), + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagDescriptionIllegalCharacters.message"), + NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagDescriptionIllegalCharacters.title"), JOptionPane.ERROR_MESSAGE); } else { tagName = tagNamesMap.get(tagDisplayName); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java index 0d0f07aa89..5829495be1 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java @@ -1,20 +1,20 @@ /* -* Autopsy Forensic Browser -* -* Copyright 2011-2017 Basis Technology Corp. -* Contact: carrier sleuthkit org -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.casemodule.services; @@ -60,7 +60,7 @@ final class TagNameDialog extends javax.swing.JDialog { initComponents(); tagNameTextField.setText(tagNameToEdit.getDisplayName()); descriptionTextArea.setText(tagNameToEdit.getDescription()); - notableCheckbox.setSelected(tagNameToEdit.getKnownStatus()== TskData.FileKnown.BAD); + notableCheckbox.setSelected(tagNameToEdit.getKnownStatus() == TskData.FileKnown.BAD); tagNameTextField.setEnabled(false); this.display(); } @@ -127,24 +127,35 @@ final class TagNameDialog extends javax.swing.JDialog { * * @param okPressed whether the OK button was pressed. */ + @Messages({"TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message=Tag descriptions may not contain commas (,) or semicolons (;)", + "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.title=Invalid character in tag description"}) private void doButtonAction(boolean okPressed) { if (okPressed) { String newTagDisplayName = tagNameTextField.getText().trim(); + String descriptionText = descriptionTextArea.getText(); if (newTagDisplayName.isEmpty()) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.message"), NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.title"), JOptionPane.ERROR_MESSAGE); return; - } + } //if a tag name contains illegal characters and is not the name of one of the standard tags if (TagsManager.containsIllegalCharacters(newTagDisplayName) && !TagNameDefinition.getStandardTagNames().contains(newTagDisplayName)) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message"), + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.title"), + JOptionPane.ERROR_MESSAGE); + return; + } else if (descriptionText.contains(",") + || descriptionText.contains(";")) { JOptionPane.showMessageDialog(null, NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.message"), NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.title"), JOptionPane.ERROR_MESSAGE); return; } + userTagDescription = descriptionTextArea.getText(); userTagDisplayName = newTagDisplayName; userTagIsNotable = notableCheckbox.isSelected(); From 4ec52d8a8476cce7ba5ab85106e856f2d7eadb81 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 22 Nov 2017 12:19:00 -0500 Subject: [PATCH 13/34] 3203 fix error message for invalid description --- .../sleuthkit/autopsy/casemodule/services/TagNameDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java index 5829495be1..e8f2275db4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java @@ -150,8 +150,8 @@ final class TagNameDialog extends javax.swing.JDialog { } else if (descriptionText.contains(",") || descriptionText.contains(";")) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.message"), - NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.title"), + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message"), + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.title"), JOptionPane.ERROR_MESSAGE); return; } From 3b030a76d873c27ac2a62c53e58771a88c201507 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 22 Nov 2017 12:32:39 -0500 Subject: [PATCH 14/34] Add new parser file --- .../hashdatabase/HashkeeperHashSetParser.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java new file mode 100644 index 0000000000..ea9ff75771 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java @@ -0,0 +1,14 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.modules.hashdatabase; + +/** + * + * @author apriestman + */ +public class HashkeeperHashSetParser { + +} From a5dca8681fac15b9ca4d9c71836ef073aad7d810 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 22 Nov 2017 16:57:18 -0500 Subject: [PATCH 15/34] 3202 rename event for tag definition changes and comment code better in caseeventlistener --- .../sleuthkit/autopsy/casemodule/Case.java | 20 +++- .../casemodule/services/TagOptionsPanel.java | 5 +- .../eventlisteners/CaseEventListener.java | 104 +++++++++++------- 3 files changed, 81 insertions(+), 48 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 2dcc532a37..52a2b7fa97 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -364,10 +364,11 @@ public class Case { */ CASE_DETAILS, /** - * The status which a Tag indicates has been changed and the new value - * of the TagNameDefinition is included. + * A tag definition has changed (e.g., description, known status). The + * old value of the PropertyChangeEvent is the display name of the tag + * definition that has changed. */ - TAG_STATUS_CHANGED; + TAG_DEFINITION_CHANGED; }; @@ -1478,9 +1479,18 @@ public class Case { eventPublisher.publish(new ContentTagDeletedEvent(deletedTag)); } - public void notifyTagStatusChanged(String changedTagName) { - eventPublisher.publish(new AutopsyEvent(Events.TAG_STATUS_CHANGED.toString(), changedTagName, changedTagName)); + /** + * Notifies case event subscribers that a tag definition has changed. + * + * This should not be called from the event dispatch thread (EDT) + * + * @param changedTagName the name of the tag definition which was changed + */ + public void notifyTagDefinitionChanged(String changedTagName) { + //leaving new value of changedTagName as null, because we do not currently support changing the display name of a tag. + eventPublisher.publish(new AutopsyEvent(Events.TAG_DEFINITION_CHANGED.toString(), changedTagName, null)); } + /** * Notifies case event subscribers that an artifact tag has been added. * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index 712fa6480d..c5458d2f76 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -423,7 +423,10 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private void sendStatusChangedEvents() { for (String modifiedTagDisplayName : updatedStatusTags) { - Case.getCurrentCase().notifyTagStatusChanged(modifiedTagDisplayName); + //if user closes their case after options have been changed but before application of them is complete don't notify + if (Case.isCaseOpen()) { + Case.getCurrentCase().notifyTagDefinitionChanged(modifiedTagDisplayName); + } } updatedStatusTags.clear(); } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index cc6dbaf142..7252ca53cc 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -98,8 +98,8 @@ final class CaseEventListener implements PropertyChangeListener { jobProcessingExecutor.submit(new DataSourceAddedTask(dbManager, evt)); } break; - case TAG_STATUS_CHANGED: { - jobProcessingExecutor.submit(new TagStatusChangeTask(evt)); + case TAG_DEFINITION_CHANGED: { + jobProcessingExecutor.submit(new TagDefinitionChangeTask(evt)); } break; case CURRENT_CASE: { @@ -298,11 +298,11 @@ final class CaseEventListener implements PropertyChangeListener { } - private final class TagStatusChangeTask implements Runnable { + private final class TagDefinitionChangeTask implements Runnable { private final PropertyChangeEvent event; - private TagStatusChangeTask(PropertyChangeEvent evt) { + private TagDefinitionChangeTask(PropertyChangeEvent evt) { event = evt; } @@ -311,73 +311,93 @@ final class CaseEventListener implements PropertyChangeListener { if (!EamDb.isEnabled()) { return; } - String modifiedTagName = (String) event.getNewValue(); - List notableTags = TagsManager.getNotableTagDisplayNames(); - TskData.FileKnown status = notableTags.contains(modifiedTagName) ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN; - /** + //get the display name of the tag that has had it's definition modified + String modifiedTagName = (String) event.getOldValue(); + + /* * Set knownBad status for all files/artifacts in the given case * that are tagged with the given tag name. */ try { TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName); - // First find any matching artifacts + //First update the artifacts + //Get all BlackboardArtifactTags with this tag name List artifactTags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName); for (BlackboardArtifactTag bbTag : artifactTags) { - List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true); - for (CorrelationAttribute eamArtifact : convertedArtifacts) { - boolean hasOtherBadTags = false; - //if the new status of the tag is unknown UNKNOWN ensure we are not changing the status of BlackboardArtifact which still have other tags with a non-unknown status - if (status == TskData.FileKnown.UNKNOWN) { - Content content = bbTag.getContent(); - if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) { + //start with assumption that none of the other tags applied to this Correlation Attribute will prevent it's status from being changed + boolean hasTagWithConflictingKnownStatus = false; + // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN + // we need to check the status of all other tags on this correlation attribute before changing + // the status of the correlation attribute in the central repository + if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) { + Content content = bbTag.getContent(); + // If the content which this Blackboard Artifact Tag is linked to is an AbstractFile with KNOWN status then + // it's status in the central reporsitory should not be changed to UNKNOWN + if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) { + continue; + } + //Get the BlackboardArtifact which this BlackboardArtifactTag has been applied to. + BlackboardArtifact bbArtifact = bbTag.getArtifact(); + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); + //get all tags which are on this blackboard artifact + for (BlackboardArtifactTag t : tags) { + //All instances of the modified tag name will be changed, they can not conflict with each other + if (t.getName().equals(tagName)) { + continue; + } + //if any other tags on this artifact are Notable in status then this artifact can not have its status changed + if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) { + //a tag with a conflicting status has been found, the status of this correlation attribute can not be modified + hasTagWithConflictingKnownStatus = true; break; } - BlackboardArtifact bbArtifact = bbTag.getArtifact(); - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact); - for (BlackboardArtifactTag t : tags) { - //avoid the possibility for threading issues if the tag whose status is currently changing is ever still in the tags manager with the old status - if (t.getName().equals(tagName)) { - continue; - } - //if any other tags on this artifact are Notable in status then this artifact can not have its status changed - if (notableTags.contains(t.getName().getDisplayName())) { - hasOtherBadTags = true; - break; - } - } } - if (!hasOtherBadTags) { - EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, status); + } + //if the Correlation Attribute will have no tags with a status which would prevent the current status from being changed + if (!hasTagWithConflictingKnownStatus) { + //Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed + //with the initial set of correlation attributes this should be a single correlation attribute + List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true); + for (CorrelationAttribute eamArtifact : convertedArtifacts) { + EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); } } } - // Now search for files + // Next update the files + List fileTags = Case.getCurrentCase().getSleuthkitCase().getContentTagsByTagName(tagName); + //Get all ContentTags with this tag name for (ContentTag contentTag : fileTags) { - boolean hasOtherBadTags = false; - //if the new status of the tag is unknown UNKNOWN ensure we are not changing the status of files which still have other tags with a Notable status - if (status == TskData.FileKnown.UNKNOWN) { + //start with assumption that none of the other tags applied to this ContentTag will prevent it's status from being changed + boolean hasTagWithConflictingKnownStatus = false; + // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN + // we need to check the status of all other tags on this file before changing + // the status of the file in the central repository + if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) { Content content = contentTag.getContent(); TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); List tags = tagsManager.getContentTagsByContent(content); + //get all tags which are on this file for (ContentTag t : tags) { - //avoid the possibility for threading issues if the tag whose status is currently changing is ever still in the tags manager with the old status + //All instances of the modified tag name will be changed, they can not conflict with each other if (t.getName().equals(tagName)) { continue; } //if any other tags on this file are Notable in status then this file can not have its status changed - if (notableTags.contains(t.getName().getDisplayName())) { - hasOtherBadTags = true; + if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) { + //a tag with a conflicting status has been found, the status of this file can not be modified + hasTagWithConflictingKnownStatus = true; break; } } } - if (!hasOtherBadTags) { + //if the file will have no tags with a status which would prevent the current status from being changed + if (!hasTagWithConflictingKnownStatus) { final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(contentTag.getContent(), - status, ""); + tagName.getKnownStatus(), ""); if (eamArtifact != null) { - EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, status); + EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); } } } From 29e953ab4fcc8e700b06eb0316f1453b068792fa Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 22 Nov 2017 17:43:59 -0500 Subject: [PATCH 16/34] Completed feature. --- .../autoingest/AutoIngestJob.java | 38 ++++++++++++++++++- .../autoingest/AutoIngestJobNodeData.java | 21 ++++++---- .../autoingest/AutoIngestManager.java | 24 ++++++++---- 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJob.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJob.java index dd4cb60377..40537d3b83 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJob.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJob.java @@ -38,10 +38,10 @@ import org.sleuthkit.autopsy.ingest.IngestJob; * ingest service. */ @ThreadSafe -public final class AutoIngestJob implements Comparable, Serializable { +final class AutoIngestJob implements Comparable, Serializable { private static final long serialVersionUID = 1L; - private static final int CURRENT_VERSION = 1; + private static final int CURRENT_VERSION = 2; private static final int DEFAULT_PRIORITY = 0; private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); @@ -82,6 +82,12 @@ public final class AutoIngestJob implements Comparable, Serializa private int numberOfCrashes; @GuardedBy("this") private StageDetails stageDetails; + + /* + * Version 2 fields. + */ + @GuardedBy("this") + private long dataSourceSize; /** * Constructs a new automated ingest job. All job state not specified in the @@ -114,6 +120,11 @@ public final class AutoIngestJob implements Comparable, Serializa this.processingStatus = ProcessingStatus.PENDING; this.numberOfCrashes = 0; this.stageDetails = this.getProcessingStageDetails(); + + /* + * Version 2 fields. + */ + this.dataSourceSize = 0; } catch (Exception ex) { throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex); } @@ -151,6 +162,11 @@ public final class AutoIngestJob implements Comparable, Serializa this.processingStatus = nodeData.getProcessingStatus(); this.numberOfCrashes = nodeData.getNumberOfCrashes(); this.stageDetails = this.getProcessingStageDetails(); + + /* + * Version 2 fields. + */ + this.dataSourceSize = nodeData.getDataSourceSize(); } catch (Exception ex) { throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex); } @@ -462,6 +478,24 @@ public final class AutoIngestJob implements Comparable, Serializa this.numberOfCrashes = numberOfCrashes; } + /** + * Gets the total size of the data source. + * + * @return The data source size. + */ + synchronized long getDataSourceSize() { + return dataSourceSize; + } + + /** + * Sets the total size of the data source. + * + * @param dataSourceSize The data source size. + */ + synchronized void setDataSourceSize(long dataSourceSize) { + this.dataSourceSize = dataSourceSize; + } + /** * Indicates whether some other job is "equal to" this job. Two jobs are * equal if they have the same manifest file path. diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java index e3ecf177e1..f367fdf553 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java @@ -114,7 +114,7 @@ final class AutoIngestJobNodeData { setProcessingStage(job.getProcessingStage()); setProcessingStageStartDate(job.getProcessingStageStartDate()); setProcessingStageDetails(job.getProcessingStageDetails()); - //DLG: + setDataSourceSize(job.getDataSourceSize()); } /** @@ -184,10 +184,13 @@ final class AutoIngestJobNodeData { this.processingStageDetailsDescription = getStringFromBuffer(buffer, TypeKind.BYTE); this.processingStageDetailsStartDate = buffer.getLong(); this.processingHostName = getStringFromBuffer(buffer, TypeKind.SHORT); - - if (this.version >= 2) { - this.dataSourceSize = buffer.getLong(); - } + } + + if (buffer.hasRemaining()) { + /* + * Get version 2 fields. + */ + this.dataSourceSize = buffer.getLong(); } } catch (BufferUnderflowException ex) { @@ -511,16 +514,18 @@ final class AutoIngestJobNodeData { } /** - * DLG: + * Gets the total size of the data source. + * + * @return The data source size. */ long getDataSourceSize() { return this.dataSourceSize; } /** - * DLG: + * Sets the total size of the data source. * - * @param DLG: + * @param dataSourceSize The data source size. */ void setDataSourceSize(long dataSourceSize) { this.dataSourceSize = dataSourceSize; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 199cb8a8db..2a0c8cd60b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -56,7 +56,6 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import java.util.stream.Collectors; import javax.annotation.concurrent.GuardedBy; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; @@ -2547,20 +2546,29 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen currentJob.setIngestJob(null); } } - - /* - * DLG: + + /** + * Gather metrics to store in auto ingest job nodes. A SleuthkitCase + * instance is used to get the content size. + * + * @param caseDb The SleuthkitCase instance. + * @param dataSource The auto ingest data source. + * + * @throws CoordinationServiceException If there's a problem retrieving + * data from the coordination + * service. + * @throws InterruptedException If the thread calling the + * coordination service is + * interrupted. */ private void collectMetrics(SleuthkitCase caseDb, AutoIngestDataSource dataSource) throws CoordinationServiceException, InterruptedException { List contentList = dataSource.getContent(); long dataSourceSize = 0; for (Content content : contentList) { - // DLG: Why multiply Content objects? - // DLG: What to do if more than one? - dataSourceSize = ((DataSource)content).getContentSize(caseDb); + dataSourceSize += ((DataSource) content).getContentSize(caseDb); } + currentJob.setDataSourceSize(dataSourceSize); AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(currentJob); - nodeData.setDataSourceSize(dataSourceSize); String manifestNodePath = currentJob.getManifest().getFilePath().toString(); coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, nodeData.toArray()); } From 8dfd028c3111694f1fd378a605615c0edbaff93c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 22 Nov 2017 17:45:01 -0500 Subject: [PATCH 17/34] 3203 add (Notable) to end of tags in generated reports --- .../casemodule/services/TagsManager.java | 5 +++++ .../sleuthkit/autopsy/report/ReportHTML.java | 4 +++- .../autopsy/report/ReportVisualPanel2.java | 5 ++++- .../autopsy/report/TableReportGenerator.java | 17 +++++++++++------ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index b28769a50a..f96fe08f23 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -71,6 +71,11 @@ public class TagsManager implements Closeable { } @NbBundle.Messages({"TagsManager.notableTagEnding.text= (Notable)"}) + /** + * Get String of text which is used to label tags as notable to the user. + * + * @return Bundle message TagsManager.notableTagEnding.text + */ public static String getNotableTagLabel(){ return Bundle.TagsManager_notableTagEnding_text(); } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index c03c37a09b..aab7eaae97 100755 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; class ReportHTML implements TableReportModule { @@ -688,7 +689,8 @@ class ReportHTML implements TableReportModule { } for (int i = 0; i < tags.size(); i++) { ContentTag tag = tags.get(i); - linkToThumbnail.append(tag.getName().getDisplayName()); + String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + linkToThumbnail.append(tag.getName().getDisplayName() + notableString); if (i != tags.size() - 1) { linkToThumbnail.append(", "); } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java index 08ec3d0151..53422c8f0d 100755 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java @@ -41,10 +41,12 @@ import javax.swing.event.ListDataListener; import org.openide.util.NbBundle; 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.BlackboardArtifact; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; final class ReportVisualPanel2 extends JPanel { @@ -102,7 +104,8 @@ final class ReportVisualPanel2 extends JPanel { } for (TagName tagName : tagNamesInUse) { - tagStates.put(tagName.getDisplayName(), Boolean.FALSE); + String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + tagStates.put(tagName.getDisplayName() + notableString, Boolean.FALSE); } tags.addAll(tagStates.keySet()); diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index 3df94c1d1c..8d5ad932ca 100755 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -39,6 +39,7 @@ import java.util.TreeSet; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; @@ -299,7 +300,8 @@ class TableReportGenerator { // Give the modules the rows for the content tags. for (ContentTag tag : tags) { // skip tags that we are not reporting on - if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { + String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + if (passesTagNamesFilter(tag.getName().getDisplayName() + notableString) == false) { continue; } @@ -310,7 +312,7 @@ class TableReportGenerator { fileName = tag.getContent().getName(); } - ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName(), fileName, tag.getComment())); + ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName() + notableString, fileName, tag.getComment())); Content content = tag.getContent(); if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile) content; @@ -376,12 +378,13 @@ class TableReportGenerator { // Give the modules the rows for the content tags. for (BlackboardArtifactTag tag : tags) { - if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { + String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + if (passesTagNamesFilter(tag.getName().getDisplayName() + notableString) == false) { continue; } List row; - row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); + row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName() + notableString, tag.getComment(), tag.getContent().getName())); tableReport.addRow(row); // check if the tag is an image that we should later make a thumbnail for @@ -963,7 +966,8 @@ class TableReportGenerator { try { List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content); for (ContentTag ct : contentTags) { - allTags.add(ct.getName().getDisplayName()); + String notableString = ct.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + allTags.add(ct.getName().getDisplayName() + notableString); } } catch (TskCoreException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); @@ -1000,7 +1004,8 @@ class TableReportGenerator { List tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); HashSet uniqueTagNames = new HashSet<>(); for (BlackboardArtifactTag tag : tags) { - uniqueTagNames.add(tag.getName().getDisplayName()); + String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + uniqueTagNames.add(tag.getName().getDisplayName() + notableString); } if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { continue; From 27b9edbd29f44a34d38ecb5b4d0d3dd8055d1e4d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 22 Nov 2017 17:51:34 -0500 Subject: [PATCH 18/34] Additional comments added. --- .../autopsy/experimental/autoingest/AutoIngestManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 2a0c8cd60b..83337c551b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -2562,12 +2562,19 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * interrupted. */ private void collectMetrics(SleuthkitCase caseDb, AutoIngestDataSource dataSource) throws CoordinationServiceException, InterruptedException { + /* + * Get the data source size and store it in the current job. + */ List contentList = dataSource.getContent(); long dataSourceSize = 0; for (Content content : contentList) { dataSourceSize += ((DataSource) content).getContentSize(caseDb); } currentJob.setDataSourceSize(dataSourceSize); + + /* + * Create node data from the current job and store it. + */ AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(currentJob); String manifestNodePath = currentJob.getManifest().getFilePath().toString(); coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, nodeData.toArray()); From 0e0ee5cd6c2cd148c5bc927af756c86f4294b30c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 22 Nov 2017 17:55:05 -0500 Subject: [PATCH 19/34] 3203 change new bundle properties to @messages syntax --- Core/src/org/sleuthkit/autopsy/actions/Bundle.properties | 2 -- Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java | 5 ++++- .../sleuthkit/autopsy/casemodule/services/Bundle.properties | 2 -- .../sleuthkit/autopsy/casemodule/services/TagNameDialog.java | 2 ++ 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties index 01d0d21b47..1cbc4b70b6 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -44,6 +44,4 @@ ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot OpenPythonModulesFolderAction.actionName.text=Python Plugins OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0} CTL_OpenPythonModulesFolderAction=Python Plugins -GetTagNameDialog.descriptionLabel.text=Description: -GetTagNameDialog.notableCheckbox.text=Tag indicates item is notable. GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index ec282dfa1f..515db21dab 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -36,6 +36,7 @@ import javax.swing.KeyStroke; import javax.swing.table.AbstractTableModel; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; @@ -44,6 +45,8 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; +@Messages({"GetTagNameDialog.descriptionLabel.text=Description:", + "GetTagNameDialog.notableCheckbox.text=Tag indicates item is notable."}) public class GetTagNameDialog extends JDialog { private static final long serialVersionUID = 1L; @@ -335,7 +338,7 @@ public class GetTagNameDialog extends JDialog { JOptionPane.ERROR_MESSAGE); } else if (userTagDescription.contains(",") || userTagDescription.contains(";")) { - JOptionPane.showMessageDialog(null, + JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagDescriptionIllegalCharacters.message"), NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagDescriptionIllegalCharacters.title"), JOptionPane.ERROR_MESSAGE); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 95fd09a57b..e9c1b5307c 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -9,9 +9,7 @@ TagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name TagOptionsPanel.tagTypesListLabel.text=Tag Names: TagOptionsPanel.deleteTagNameButton.text=Delete Tag TagOptionsPanel.newTagNameButton.text=New Tag -TagNameDialog.descriptionLabel.text=Description: TagNameDialog.okButton.text=OK TagNameDialog.cancelButton.text=Cancel TagNameDialog.tagNameTextField.text= TagNameDialog.newTagNameLabel.text=Name: -TagNameDialog.notableCheckbox.text=Tag indicates item is notable. \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java index e8f2275db4..4949be2507 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java @@ -31,6 +31,8 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.TskData; +@Messages({"TagNameDialog.descriptionLabel.text=Description:", + "TagNameDialog.notableCheckbox.text=Tag indicates item is notable."}) final class TagNameDialog extends javax.swing.JDialog { private static final long serialVersionUID = 1L; From 605994d64174e64520e45938fbf95f36a4bc415a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 22 Nov 2017 18:17:09 -0500 Subject: [PATCH 20/34] 3224 add Databases node to File Types by Extension tree --- .../org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java | 5 +++++ .../sleuthkit/autopsy/datamodel/FileTypesByExtension.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java index 4195b33008..eafa8377b2 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java @@ -38,6 +38,7 @@ public class FileTypeExtensions { private final static List WEB_EXTENSIONS = Arrays.asList(".html", ".htm", ".css", ".js", ".php", ".aspx"); //NON-NLS private final static List PDF_EXTENSIONS = Arrays.asList(".pdf"); //NON-NLS private final static List ARCHIVE_EXTENSIONS = Arrays.asList(".zip", ".rar", ".7zip", ".7z", ".arj", ".tar", ".gzip", ".bzip", ".bzip2", ".cab", ".jar", ".cpio", ".ar", ".gz", ".tgz", ".bz2"); //NON-NLS + private final static List DATABASE_EXTENSIONS = Arrays.asList(".db", ".db3", ".sqlite", ".sqlite3"); //NON-NLS public static List getImageExtensions() { return IMAGE_EXTENSIONS; @@ -75,6 +76,10 @@ public class FileTypeExtensions { return ARCHIVE_EXTENSIONS; } + public static List getDatabaseExtensions() { + return DATABASE_EXTENSIONS; + } + private FileTypeExtensions() { } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 305da8e953..3c79626e81 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -34,6 +34,7 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.UserPreferences; @@ -423,6 +424,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { } // root node filters + @Messages({"FileTypeExtensionFilters.tskDatabaseFilter.text=Databases"}) public static enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface { TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", //NON-NLS @@ -437,6 +439,9 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"), FileTypeExtensions.getArchiveExtensions()), + TSK_DATABASE_FILTER(3, "TSK_DATABASE_FILTER", //NON-NLS + NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDatabaseFilter.text"), + FileTypeExtensions.getDatabaseExtensions()), TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"), Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS From d7c59a0356ce7c329bf388a7fa93b0bc5061abb1 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 22 Nov 2017 18:19:34 -0500 Subject: [PATCH 21/34] 3224 fix IDs for FileTypesByExtension filter enum --- .../sleuthkit/autopsy/datamodel/FileTypesByExtension.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 3c79626e81..2341fff12c 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -439,13 +439,13 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"), FileTypeExtensions.getArchiveExtensions()), - TSK_DATABASE_FILTER(3, "TSK_DATABASE_FILTER", //NON-NLS + TSK_DATABASE_FILTER(4, "TSK_DATABASE_FILTER", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDatabaseFilter.text"), FileTypeExtensions.getDatabaseExtensions()), - TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS + TSK_DOCUMENT_FILTER(5, "TSK_DOCUMENT_FILTER", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"), Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS - TSK_EXECUTABLE_FILTER(3, "TSK_EXECUTABLE_FILTER", //NON-NLS + TSK_EXECUTABLE_FILTER(6, "TSK_EXECUTABLE_FILTER", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"), FileTypeExtensions.getExecutableExtensions()); //NON-NLS From 81d35de2c49b4792484d161944f2b862255330f5 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 27 Nov 2017 10:06:55 -0500 Subject: [PATCH 22/34] Add support for importing hashkeeper hash sets and md5sum output text files --- .../HashDbImportDatabaseDialog.java | 22 +-- .../hashdatabase/HashkeeperHashSetParser.java | 132 +++++++++++++++++- .../hashdatabase/IdxHashSetParser.java | 13 +- .../ImportCentralRepoDbProgressDialog.java | 4 +- 4 files changed, 141 insertions(+), 30 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index db70d1114d..d2af9533be 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -84,25 +84,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private void initFileChooser() { fileChooser.setDragEnabled(false); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - updateFileChooserFilter(); + String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS + FileNameExtensionFilter filter = new FileNameExtensionFilter( + NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION); + fileChooser.setFileFilter(filter); fileChooser.setMultiSelectionEnabled(false); } - - @NbBundle.Messages({"HashDbImportDatabaseDialog.centralRepoExtFilter.text=Hash Database File (.kdb, .idx or .hash)"}) - private void updateFileChooserFilter() { - fileChooser.resetChoosableFileFilters(); - if(centralRepoRadioButton.isSelected()){ - String[] EXTENSION = new String[]{"kdb", "idx", "hash", "Hash"}; //NON-NLS - FileNameExtensionFilter filter = new FileNameExtensionFilter( - NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.centralRepoExtFilter.text"), EXTENSION); - fileChooser.setFileFilter(filter); - } else { - String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS - FileNameExtensionFilter filter = new FileNameExtensionFilter( - NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION); - fileChooser.setFileFilter(filter); - } - } private void display() { Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); @@ -409,7 +396,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { hashDbFolder.mkdir(); } fileChooser.setCurrentDirectory(hashDbFolder); - updateFileChooserFilter(); if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { File databaseFile = fileChooser.getSelectedFile(); try { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java index ea9ff75771..e325bc94da 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java @@ -1,14 +1,134 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011 - 2017 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.modules.hashdatabase; +import java.io.File; +import java.io.InputStreamReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.logging.Level; +import java.util.Iterator; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TskCoreException; + /** - * - * @author apriestman + * Parser for Hashkeeper hash sets (*.hsh) */ -public class HashkeeperHashSetParser { +public class HashkeeperHashSetParser implements HashSetParser { + private String filename; + private InputStreamReader inputStreamReader; + private CSVParser csvParser; + private final long expectedHashCount; // Number of hashes we expect to read from the file + private final Iterator recordIterator; + private final int hashColumnIndex; // The index of the hash column + + HashkeeperHashSetParser(String filename) throws TskCoreException { + this.filename = filename; + + try{ + // Estimate the total number of hashes in the file + File importFile = new File(filename); + long fileSize = importFile.length(); + expectedHashCount = fileSize / 75 + 1; // As a rough estimate, assume 75 bytes per line. We add one to prevent this from being zero + + // Create the parser + inputStreamReader = new InputStreamReader(new FileInputStream(filename)); //NON-NLS + csvParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(inputStreamReader); + if( ! csvParser.getHeaderMap().keySet().contains("hash")){ + close(); + throw new TskCoreException("Hashkeeper file format invalid - does not contain 'hash' column"); + } + + // For efficiency, store the index of the hash column + hashColumnIndex = csvParser.getHeaderMap().get("hash"); + + // Make an iterator to loop over the entries + recordIterator = csvParser.getRecords().listIterator(); + + // We're ready to use recordIterator to get each hash + + } catch (IOException ex){ + close(); + throw new TskCoreException("Error reading " + filename, ex); + } + } + + /** + * Get the next hash to import + * + * @return The hash as a string, or null if the end of file was reached + * without error + * @throws TskCoreException + */ + @Override + public String getNextHash() throws TskCoreException { + if(recordIterator.hasNext()){ + CSVRecord record = recordIterator.next(); + String hash = record.get(hashColumnIndex); + + if (hash.length() != 32) { + throw new TskCoreException("Hash has incorrect length: " + hash); + } + + return (hash); + } + return null; + } + + /** + * Check if there are more hashes to read + * + * @return true if we've read all expected hash values, false otherwise + */ + @Override + public boolean doneReading() { + return (! recordIterator.hasNext()); + } + + /** + * Get the expected number of hashes in the file. This number can be an + * estimate. + * + * @return The expected hash count + */ + @Override + public long getExpectedHashCount() { + return expectedHashCount; + } + + /** + * Closes the import file + */ + @Override + public final void close() { + if(inputStreamReader != null){ + try{ + inputStreamReader.close(); + } catch (IOException ex) { + Logger.getLogger(EncaseHashSetParser.class.getName()).log(Level.SEVERE, "Error closing Hashkeeper hash set " + filename, ex); + } finally { + inputStreamReader = null; + } + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java index 0c1b694e1b..815e98e324 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java @@ -28,7 +28,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; /** - * Parser for idx files (*.idx) + * Parser for idx files and md5sum files (*.idx or *.txt) + * This parsers lines that start with md5 hashes and ignores any others */ class IdxHashSetParser implements HashSetParser { @@ -49,6 +50,7 @@ class IdxHashSetParser implements HashSetParser { File importFile = new File(filename); long fileSize = importFile.length(); totalHashes = fileSize / 0x33 + 1; // IDX file lines are generally 0x33 bytes long. We add one to prevent this from being zero + // MD5sum output lines should be close enough to that (0x20 byte hash + filename) } /** @@ -65,14 +67,15 @@ class IdxHashSetParser implements HashSetParser { try { while ((line = reader.readLine()) != null) { - String[] parts = line.split("\\|"); + // idx files have a pipe after the hash, md5sum files should have a space + String[] parts = line.split("\\|| "); - // Header lines start with a 41 character dummy hash, 1 character longer than a SHA-1 hash - if (parts.length != 2 || parts[0].length() == 41) { + String hashStr = parts[0].toLowerCase(); + if(! hashStr.matches("^[0-9a-f]{32}$")){ continue; } - return parts[0].toLowerCase(); + return hashStr; } } catch (IOException ex) { throw new TskCoreException("Error reading file " + filename, ex); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index a2e9522893..0ea2776328 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -213,12 +213,14 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P // Create the hash set parser HashSetParser hashSetParser; - if (importFileName.toLowerCase().endsWith(".idx")) { + if (importFileName.toLowerCase().endsWith(".idx") || importFileName.toLowerCase().endsWith(".txt")) { hashSetParser = new IdxHashSetParser(importFileName); } else if(importFileName.toLowerCase().endsWith(".hash")){ hashSetParser = new EncaseHashSetParser(importFileName); } else if(importFileName.toLowerCase().endsWith(".kdb")){ hashSetParser = new KdbHashSetParser(importFileName); + } else if(importFileName.toLowerCase().endsWith(".hsh")){ + hashSetParser = new HashkeeperHashSetParser(importFileName); } else { // We've gotten here with a format that can't be processed throw new TskCoreException("Hash set to import is an unknown format : " + importFileName); From 05244f6fa146c13c48ae3a2e1a725e9be8954d37 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 27 Nov 2017 10:09:19 -0500 Subject: [PATCH 23/34] Cleanup --- .../hashdatabase/HashkeeperHashSetParser.java | 37 +++++++++---------- .../hashdatabase/IdxHashSetParser.java | 6 +-- .../ImportCentralRepoDbProgressDialog.java | 8 ++-- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java index e325bc94da..e66af62eb3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java @@ -34,45 +34,44 @@ import org.sleuthkit.datamodel.TskCoreException; * Parser for Hashkeeper hash sets (*.hsh) */ public class HashkeeperHashSetParser implements HashSetParser { - + private String filename; private InputStreamReader inputStreamReader; private CSVParser csvParser; private final long expectedHashCount; // Number of hashes we expect to read from the file private final Iterator recordIterator; private final int hashColumnIndex; // The index of the hash column - + HashkeeperHashSetParser(String filename) throws TskCoreException { this.filename = filename; - - try{ + + try { // Estimate the total number of hashes in the file File importFile = new File(filename); long fileSize = importFile.length(); expectedHashCount = fileSize / 75 + 1; // As a rough estimate, assume 75 bytes per line. We add one to prevent this from being zero - + // Create the parser inputStreamReader = new InputStreamReader(new FileInputStream(filename)); //NON-NLS csvParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(inputStreamReader); - if( ! csvParser.getHeaderMap().keySet().contains("hash")){ + if (!csvParser.getHeaderMap().keySet().contains("hash")) { close(); throw new TskCoreException("Hashkeeper file format invalid - does not contain 'hash' column"); } - + // For efficiency, store the index of the hash column hashColumnIndex = csvParser.getHeaderMap().get("hash"); // Make an iterator to loop over the entries recordIterator = csvParser.getRecords().listIterator(); - + // We're ready to use recordIterator to get each hash - - } catch (IOException ex){ + } catch (IOException ex) { close(); throw new TskCoreException("Error reading " + filename, ex); } } - + /** * Get the next hash to import * @@ -82,7 +81,7 @@ public class HashkeeperHashSetParser implements HashSetParser { */ @Override public String getNextHash() throws TskCoreException { - if(recordIterator.hasNext()){ + if (recordIterator.hasNext()) { CSVRecord record = recordIterator.next(); String hash = record.get(hashColumnIndex); @@ -91,7 +90,7 @@ public class HashkeeperHashSetParser implements HashSetParser { } return (hash); - } + } return null; } @@ -102,7 +101,7 @@ public class HashkeeperHashSetParser implements HashSetParser { */ @Override public boolean doneReading() { - return (! recordIterator.hasNext()); + return (!recordIterator.hasNext()); } /** @@ -120,15 +119,15 @@ public class HashkeeperHashSetParser implements HashSetParser { * Closes the import file */ @Override - public final void close() { - if(inputStreamReader != null){ - try{ + public final void close() { + if (inputStreamReader != null) { + try { inputStreamReader.close(); } catch (IOException ex) { - Logger.getLogger(EncaseHashSetParser.class.getName()).log(Level.SEVERE, "Error closing Hashkeeper hash set " + filename, ex); + Logger.getLogger(HashkeeperHashSetParser.class.getName()).log(Level.SEVERE, "Error closing Hashkeeper hash set " + filename, ex); } finally { inputStreamReader = null; - } + } } } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java index 815e98e324..0db5442c0c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java @@ -28,8 +28,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; /** - * Parser for idx files and md5sum files (*.idx or *.txt) - * This parsers lines that start with md5 hashes and ignores any others + * Parser for idx files and md5sum files (*.idx or *.txt) This parsers lines + * that start with md5 hashes and ignores any others */ class IdxHashSetParser implements HashSetParser { @@ -71,7 +71,7 @@ class IdxHashSetParser implements HashSetParser { String[] parts = line.split("\\|| "); String hashStr = parts[0].toLowerCase(); - if(! hashStr.matches("^[0-9a-f]{32}$")){ + if (!hashStr.matches("^[0-9a-f]{32}$")) { continue; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index 0ea2776328..37d3a20009 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -215,12 +215,12 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P HashSetParser hashSetParser; if (importFileName.toLowerCase().endsWith(".idx") || importFileName.toLowerCase().endsWith(".txt")) { hashSetParser = new IdxHashSetParser(importFileName); - } else if(importFileName.toLowerCase().endsWith(".hash")){ + } else if (importFileName.toLowerCase().endsWith(".hash")) { hashSetParser = new EncaseHashSetParser(importFileName); - } else if(importFileName.toLowerCase().endsWith(".kdb")){ + } else if (importFileName.toLowerCase().endsWith(".kdb")) { hashSetParser = new KdbHashSetParser(importFileName); - } else if(importFileName.toLowerCase().endsWith(".hsh")){ - hashSetParser = new HashkeeperHashSetParser(importFileName); + } else if (importFileName.toLowerCase().endsWith(".hsh")) { + hashSetParser = new HashkeeperHashSetParser(importFileName); } else { // We've gotten here with a format that can't be processed throw new TskCoreException("Hash set to import is an unknown format : " + importFileName); From 06b8b51e51b457c430279706615e26416d6b4149 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 27 Nov 2017 10:20:32 -0500 Subject: [PATCH 24/34] 3203 fix comment to reflect that tag status applies outside of CR --- .../autopsy/casemodule/services/TagNameDefinition.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index 880354f77b..e1d81d2b65 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -107,8 +107,7 @@ final class TagNameDefinition implements Comparable { } /** - * The status which items which have this tag applied to them should have in - * the central repository. + * The status which will be applied to items with this tag. * * @return a value of TskData.FileKnown which is associated with this tag */ From 6487af2f57ea43cc4729b5bf0d068acc522f7b07 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 28 Nov 2017 11:04:47 -0500 Subject: [PATCH 25/34] Add a default organization when the central repo db is created --- .../datamodel/EamDbUtil.java | 45 ++++++++++++++++++- .../datamodel/PostgresEamDbSettings.java | 3 +- .../datamodel/SqliteEamDbSettings.java | 3 +- .../ManageOrganizationsDialog.java | 20 ++++++--- .../HashDbCreateDatabaseDialog.java | 7 ++- .../HashDbImportDatabaseDialog.java | 7 ++- 6 files changed, 72 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java index 5d70d6fdac..49f49f9d38 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java @@ -37,6 +37,7 @@ public class EamDbUtil { private final static Logger LOGGER = Logger.getLogger(EamDbUtil.class.getName()); private static final String CENTRAL_REPO_NAME = "CentralRepository"; private static final String CENTRAL_REPO_USE_KEY = "db.useCentralRepo"; + private static final String DEFAULT_ORG_NAME = "Not Specified"; /** * Close the prepared statement. @@ -175,11 +176,51 @@ public class EamDbUtil { return true; } + /** + * Check whether the given org is the default organization. + * + * @param org + * @return true if it is the default org, false otherwise + */ + public static boolean isDefaultOrg(EamOrganization org) { + return DEFAULT_ORG_NAME.equals(org.getName()); + } + + /** + * Add the default organization to the database + * + * @param conn + * @return true if successful, false otherwise + */ + static boolean insertDefaultOrganization(Connection conn) { + if (null == conn) { + return false; + } + + PreparedStatement preparedStatement = null; + String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?)"; + try { + preparedStatement = conn.prepareStatement(sql); + preparedStatement.setString(1, DEFAULT_ORG_NAME); + preparedStatement.setString(2, ""); + preparedStatement.setString(3, ""); + preparedStatement.setString(4, ""); + preparedStatement.executeUpdate(); + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, "Error adding default organization", ex); + return false; + } finally { + EamDbUtil.closePreparedStatement(preparedStatement); + } + + return true; + } + /** * If the Central Repos use has been enabled. * * @return true if the Central Repo may be configured, false if it should - * not be able to be + * not be able to be */ public static boolean useCentralRepo() { return Boolean.parseBoolean(ModuleSettings.getConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY)); @@ -190,7 +231,7 @@ public class EamDbUtil { * configured. * * @param centralRepoCheckBoxIsSelected - true if the central repo can be - * used + * used */ public static void setUseCentralRepo(boolean centralRepoCheckBoxIsSelected) { ModuleSettings.setConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY, Boolean.toString(centralRepoCheckBoxIsSelected)); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java index bfb3f04b32..324cc2ac7d 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java @@ -485,7 +485,8 @@ public final class PostgresEamDbSettings { } boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn) - && EamDbUtil.insertSchemaVersion(conn); + && EamDbUtil.insertSchemaVersion(conn) + && EamDbUtil.insertDefaultOrganization(conn); EamDbUtil.closeConnection(conn); return result; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java index b4ea1aa8a2..c7a3730e46 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java @@ -434,7 +434,8 @@ public final class SqliteEamDbSettings { } boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn) - && EamDbUtil.insertSchemaVersion(conn); + && EamDbUtil.insertSchemaVersion(conn) + && EamDbUtil.insertDefaultOrganization(conn); EamDbUtil.closeConnection(conn); return result; } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java index ad6c26e4d8..9055485e2f 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java @@ -35,6 +35,7 @@ import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.coreutils.Logger; @@ -72,7 +73,7 @@ public final class ManageOrganizationsDialog extends JDialog { organizationList.setModel(rulesListModel); organizationList.addListSelectionListener(new OrganizationListSelectionListener()); populateList(); - setButtonsEnabled(organizationList.getSelectedValue() != null); + setButtonsEnabled(organizationList.getSelectedValue()); newOrg = null; } catch (EamDbException ex) { Exceptions.printStackTrace(ex); @@ -421,9 +422,15 @@ public final class ManageOrganizationsDialog extends JDialog { return newOrg; } - private void setButtonsEnabled(boolean isSelected) { - editButton.setEnabled(isSelected); - deleteButton.setEnabled(isSelected); + private void setButtonsEnabled(EamOrganization selectedOrg) { + boolean isSelected = (selectedOrg != null); + boolean isDefaultOrg = false; + if(selectedOrg != null){ + isDefaultOrg = EamDbUtil.isDefaultOrg(selectedOrg); + } + + editButton.setEnabled(isSelected && (! isDefaultOrg)); + deleteButton.setEnabled(isSelected && (! isDefaultOrg)); } /** @@ -436,9 +443,8 @@ public final class ManageOrganizationsDialog extends JDialog { if (e.getValueIsAdjusting()) { return; } - EamOrganization selected = organizationList.getSelectedValue(); - boolean isSelected = (selected != null); - setButtonsEnabled(isSelected); + EamOrganization selected = organizationList.getSelectedValue(); + setButtonsEnabled(selected); if (selected != null) { orgNameTextField.setText(selected.getName()); pocNameTextField.setText(selected.getPocName()); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index 17a69930a2..13dd9bcd63 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -33,6 +33,7 @@ import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog; @@ -154,8 +155,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { orgs = dbManager.getOrganizations(); orgs.forEach((org) -> { orgComboBox.addItem(org.getName()); + if(EamDbUtil.isDefaultOrg(org)){ + orgComboBox.setSelectedItem(org.getName()); + selectedOrg = org; + } }); - if (!orgs.isEmpty()) { + if ((selectedOrg == null) && (!orgs.isEmpty())) { selectedOrg = orgs.get(0); } } catch (EamDbException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index db70d1114d..95f83229b1 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -34,6 +34,7 @@ import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog; import org.sleuthkit.autopsy.coreutils.Logger; @@ -148,8 +149,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { orgs = dbManager.getOrganizations(); orgs.forEach((org) -> { orgComboBox.addItem(org.getName()); + if(EamDbUtil.isDefaultOrg(org)){ + orgComboBox.setSelectedItem(org.getName()); + selectedOrg = org; + } }); - if (!orgs.isEmpty()) { + if ((selectedOrg == null) && (!orgs.isEmpty())) { selectedOrg = orgs.get(0); } } catch (EamDbException ex) { From 917fd9048a187614c58ac1135c4d1886629d1cc2 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 28 Nov 2017 14:27:49 -0500 Subject: [PATCH 26/34] Cleanup of import hash dialog --- .../modules/hashdatabase/Bundle.properties | 8 +- .../HashDbImportDatabaseDialog.form | 172 +++++++++--------- .../HashDbImportDatabaseDialog.java | 142 ++++++++------- 3 files changed, 166 insertions(+), 156 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index 3ec2961927..b3eb5608ae 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -17,7 +17,7 @@ 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 -HashDbImportDatabaseDialog.jLabel1.text=Hash Set Name: +HashDbImportDatabaseDialog.jLabel1.text=Name: HashDbImportDatabaseDialog.databasePathTextField.text= HashDbImportDatabaseDialog.knownBadRadioButton.text=Notable HashDbImportDatabaseDialog.jLabel2.text=Type of database\: @@ -230,9 +230,9 @@ HashDbImportDatabaseDialog.lbOrg.text=Source Organization: HashDbImportDatabaseDialog.readOnlyCheckbox.text=Make database read-only HashDbImportDatabaseDialog.orgButton.text=Manage Organizations HashDbImportDatabaseDialog.versionTextField.text= -HashDbImportDatabaseDialog.fileTypeRadioButton.text=File -HashDbImportDatabaseDialog.centralRepoRadioButton.text=Central Repository -HashDbImportDatabaseDialog.jLabel4.text=Location: +HashDbImportDatabaseDialog.fileTypeRadioButton.text=Local +HashDbImportDatabaseDialog.centralRepoRadioButton.text=Remote (Central Repository) +HashDbImportDatabaseDialog.jLabel4.text=Destination: HashDbCreateDatabaseDialog.jLabel4.text=Location: HashDbCreateDatabaseDialog.fileTypeRadioButton.text=File HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Central Repository diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form index 682ec13c34..69601b784b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form @@ -33,64 +33,63 @@ - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - + + - + + + + + + @@ -99,51 +98,58 @@ - - - - - - - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index db70d1114d..f84d17bd46 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -303,50 +303,50 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(0, 325, Short.MAX_VALUE) - .addComponent(okButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cancelButton)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2) + .addGroup(layout.createSequentialGroup() + .addGap(19, 19, 19) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(knownRadioButton) + .addComponent(knownBadRadioButton))) + .addComponent(sendIngestMessagesCheckbox) + .addComponent(readOnlyCheckbox)) + .addGap(177, 177, 177)) .addGroup(layout.createSequentialGroup() .addComponent(lbOrg) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(orgComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(orgButton)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel1) - .addComponent(lbVersion)) - .addGap(2, 2, 2) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(versionTextField) - .addComponent(hashSetNameTextField))) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel3) - .addComponent(jLabel4)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(fileTypeRadioButton) - .addGap(26, 26, 26) - .addComponent(centralRepoRadioButton)) - .addComponent(databasePathTextField)))) + .addComponent(orgButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED))) + .addComponent(okButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(openButton)) + .addComponent(cancelButton)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel2) + .addComponent(jLabel3) + .addComponent(jLabel4)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(19, 19, 19) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(knownRadioButton) - .addComponent(knownBadRadioButton))) - .addComponent(sendIngestMessagesCheckbox) - .addComponent(readOnlyCheckbox)) - .addGap(0, 0, Short.MAX_VALUE))) + .addComponent(fileTypeRadioButton) + .addGap(26, 26, 26) + .addComponent(centralRepoRadioButton)) + .addComponent(databasePathTextField)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(openButton)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addComponent(lbVersion)) + .addGap(40, 40, 40) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(versionTextField) + .addComponent(hashSetNameTextField)) + .addGap(142, 142, 142))) .addContainerGap()) ); @@ -354,45 +354,49 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(fileTypeRadioButton) - .addComponent(centralRepoRadioButton) - .addComponent(jLabel4)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(openButton) .addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel3)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) - .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbVersion)) - .addGap(9, 9, 9) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(orgButton) - .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbOrg)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(knownBadRadioButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(readOnlyCheckbox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(sendIngestMessagesCheckbox) - .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()) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .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()) + .addGroup(layout.createSequentialGroup() + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(fileTypeRadioButton) + .addComponent(centralRepoRadioButton) + .addComponent(jLabel4)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lbVersion) + .addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(5, 5, 5) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(orgButton) + .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbOrg)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(knownRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(knownBadRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(readOnlyCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(sendIngestMessagesCheckbox) + .addContainerGap(32, Short.MAX_VALUE)))) ); pack(); From ce5f0fb4ffc0ee8f8db10d67511b7bfab9471831 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 28 Nov 2017 14:49:33 -0500 Subject: [PATCH 27/34] Updated the new database panel and main options panel --- .../modules/hashdatabase/Bundle.properties | 12 +- .../HashDbImportDatabaseDialog.form | 111 +++++++++--------- .../HashDbImportDatabaseDialog.java | 95 +++++++-------- .../hashdatabase/HashLookupSettingsPanel.form | 41 +++---- .../hashdatabase/HashLookupSettingsPanel.java | 36 +++--- 5 files changed, 149 insertions(+), 146 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index b3eb5608ae..7e4b10fc5d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -39,7 +39,7 @@ HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest inbox mes HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest inbox message for each hit HashDbImportDatabaseDialog.hashSetNameTextField.text= HashDbImportDatabaseDialog.openButton.text=Open... -HashDbCreateDatabaseDialog.jLabel3.text=Hash Set Name: +HashDbCreateDatabaseDialog.jLabel3.text=Name: HashDbCreateDatabaseDialog.okButton.text=OK HashDbCreateDatabaseDialog.databasePathTextField.text= AddContentToHashDbAction.ContentMenu.noHashDbsConfigd=No hash databases configured @@ -205,7 +205,7 @@ HashLookupSettingsPanel.typeLabel.text=Type: HashLookupSettingsPanel.locationLabel.text=Database Path: HashLookupSettingsPanel.hashDbLocationLabel.text=No database selected HashLookupSettingsPanel.hashDbNameLabel.text=No database selected -HashLookupSettingsPanel.nameLabel.text=Hash Set Name: +HashLookupSettingsPanel.nameLabel.text=Name: HashLookupSettingsPanel.hashDatabasesLabel.text=Hash Databases: HashLookupSettingsPanel.importDatabaseButton.toolTipText= HashLookupSettingsPanel.importDatabaseButton.text=Import database @@ -229,13 +229,13 @@ HashDbImportDatabaseDialog.lbVersion.text=Version: HashDbImportDatabaseDialog.lbOrg.text=Source Organization: HashDbImportDatabaseDialog.readOnlyCheckbox.text=Make database read-only HashDbImportDatabaseDialog.orgButton.text=Manage Organizations -HashDbImportDatabaseDialog.versionTextField.text= +HashDbImportDatabaseDialog.versionTextField.text=1.0 HashDbImportDatabaseDialog.fileTypeRadioButton.text=Local HashDbImportDatabaseDialog.centralRepoRadioButton.text=Remote (Central Repository) HashDbImportDatabaseDialog.jLabel4.text=Destination: -HashDbCreateDatabaseDialog.jLabel4.text=Location: -HashDbCreateDatabaseDialog.fileTypeRadioButton.text=File -HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Central Repository +HashDbCreateDatabaseDialog.jLabel4.text=Destination: +HashDbCreateDatabaseDialog.fileTypeRadioButton.text=Local +HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Remote (Central Repository) HashDbCreateDatabaseDialog.lbOrg.text=Source Organization: HashDbCreateDatabaseDialog.orgButton.text=Manage Organizations HashDbCreateDatabaseDialog.databasePathLabel.text=Database Path: diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form index 69601b784b..dbb9f7b4e3 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form @@ -32,36 +32,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -73,26 +43,61 @@ + + + + + + + - - - - + - - + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + - + - @@ -101,21 +106,13 @@ - + + - - - - - - - - - @@ -147,9 +144,17 @@ - + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index f84d17bd46..2c43be75ee 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -302,29 +302,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .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() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel2) - .addGroup(layout.createSequentialGroup() - .addGap(19, 19, 19) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(knownRadioButton) - .addComponent(knownBadRadioButton))) - .addComponent(sendIngestMessagesCheckbox) - .addComponent(readOnlyCheckbox)) - .addGap(177, 177, 177)) - .addGroup(layout.createSequentialGroup() - .addComponent(lbOrg) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(orgComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(orgButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED))) - .addComponent(okButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cancelButton)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jLabel3) @@ -334,20 +311,46 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addGroup(layout.createSequentialGroup() .addComponent(fileTypeRadioButton) .addGap(26, 26, 26) - .addComponent(centralRepoRadioButton)) - .addComponent(databasePathTextField)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(openButton)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(centralRepoRadioButton) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addComponent(databasePathTextField) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(openButton) + .addContainerGap()))) + .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel1) - .addComponent(lbVersion)) - .addGap(40, 40, 40) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(versionTextField) - .addComponent(hashSetNameTextField)) - .addGap(142, 142, 142))) - .addContainerGap()) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(sendIngestMessagesCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(okButton)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(lbOrg) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(orgComboBox, 0, 121, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(orgButton)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addComponent(lbVersion)) + .addGap(40, 40, 40) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(versionTextField) + .addComponent(hashSetNameTextField)))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(cancelButton) + .addContainerGap()) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2) + .addComponent(readOnlyCheckbox) + .addGroup(layout.createSequentialGroup() + .addGap(19, 19, 19) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(knownRadioButton) + .addComponent(knownBadRadioButton)))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton}); @@ -357,18 +360,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(openButton) .addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel3)) + .addComponent(jLabel3) + .addComponent(openButton)) + .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .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()) - .addGroup(layout.createSequentialGroup() - .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(fileTypeRadioButton) .addComponent(centralRepoRadioButton) @@ -396,7 +393,13 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addComponent(readOnlyCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(sendIngestMessagesCheckbox) - .addContainerGap(32, Short.MAX_VALUE)))) + .addGap(0, 21, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(okButton)))) + .addContainerGap()) ); pack(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form index 5be552d274..d32cbf57d7 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form @@ -105,28 +105,6 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -143,6 +121,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index b774ad83c8..1adb75594d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -787,24 +787,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addGroup(jPanel1Layout.createSequentialGroup() .addGap(10, 10, 10) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(locationLabel) - .addComponent(typeLabel) - .addComponent(versionLabel) - .addComponent(orgLabel) - .addComponent(readOnlyLabel)) - .addGap(55, 55, 55) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(hashDbVersionLabel) - .addComponent(hashDbOrgLabel) - .addComponent(hashDbReadOnlyLabel))) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(nameLabel) - .addGap(53, 53, 53) - .addComponent(hashDbNameLabel)) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(indexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -816,7 +798,23 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(10, 10, 10) - .addComponent(addHashesToDatabaseButton)))) + .addComponent(addHashesToDatabaseButton)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(locationLabel) + .addComponent(typeLabel) + .addComponent(versionLabel) + .addComponent(orgLabel) + .addComponent(readOnlyLabel) + .addComponent(nameLabel)) + .addGap(55, 55, 55) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(hashDbNameLabel) + .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(hashDbVersionLabel) + .addComponent(hashDbOrgLabel) + .addComponent(hashDbReadOnlyLabel))))) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(70, 70, 70) .addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE)) From a6d312663c4bc4cd598efe730aac6c8bd9b384ed Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 28 Nov 2017 15:44:31 -0500 Subject: [PATCH 28/34] 3158 Agency Logo preview now present in options panel --- .../corecomponents/AutopsyOptionsPanel.form | 543 ++++++++++-------- .../corecomponents/AutopsyOptionsPanel.java | 332 +++++++---- .../autopsy/corecomponents/Bundle.properties | 3 +- 3 files changed, 539 insertions(+), 339 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form index 06607d7d9b..2e618379e4 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form @@ -22,12 +22,18 @@ - + + + + - + + + + @@ -46,247 +52,336 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - - - - - - - - + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java index 4f95087f66..4862846b13 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java @@ -18,9 +18,18 @@ */ package org.sleuthkit.autopsy.corecomponents; +import java.awt.image.BufferedImage; import java.io.File; +import java.io.IOException; +import java.util.logging.Level; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; import javax.swing.JFileChooser; +import javax.swing.JOptionPane; import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.ModuleSettings; @@ -29,16 +38,23 @@ import org.sleuthkit.autopsy.report.ReportBranding; /** * Options panel that allow users to set application preferences. */ +@Messages({"AutopsyOptionsPanel.agencyLogoPreview.text=
No logo
selected
", + "AutopsyOptionsPanel.logoPanel.border.title=Logo", + "AutopsyOptionsPanel.viewPanel.border.title=View", + "AutopsyOptionsPanel.invalidImageFile.msg=The selected file was not able to be used as an agency logo.", + "AutopsyOptionsPanel.invalidImageFile.title=Invalid Image File"}) final class AutopsyOptionsPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; private final JFileChooser fc; + private static final Logger logger = Logger.getLogger(AutopsyOptionsPanel.class.getName()); AutopsyOptionsPanel() { initComponents(); fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setMultiSelectionEnabled(false); + fc.setAcceptAllFileFilterUsed(false); fc.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR)); } @@ -53,7 +69,28 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { boolean useLocalTime = UserPreferences.displayTimesInLocalTime(); useLocalTimeRB.setSelected(useLocalTime); useGMTTimeRB.setSelected(!useLocalTime); - agencyLogoPathField.setText(ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP)); + String path = ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP); + try { + updateAgencyLogo(path); + } catch (IOException ex) { + logger.log(Level.WARNING, "Error loading image from previously saved agency logo path", ex); + } + } + + private void updateAgencyLogo(String path) throws IOException { + agencyLogoPathField.setText(path); + ImageIcon agencyLogoIcon = new ImageIcon(); + agencyLogoPreview.setText(Bundle.AutopsyOptionsPanel_agencyLogoPreview_text()); + if (!agencyLogoPathField.getText().isEmpty()) { + File file = new File(agencyLogoPathField.getText()); + if (file.exists()) { + BufferedImage image = ImageIO.read(file); //create it as an image first to support BMP files + agencyLogoIcon = new ImageIcon(image.getScaledInstance(64, 64, 4)); + agencyLogoPreview.setText(""); + } + } + agencyLogoPreview.setIcon(agencyLogoIcon); + agencyLogoPreview.repaint(); } void store() { @@ -64,8 +101,8 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected()); UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected()); if (!agencyLogoPathField.getText().isEmpty()) { - File image = new File(agencyLogoPathField.getText()); - if (image.exists()) { + File file = new File(agencyLogoPathField.getText()); + if (file.exists()) { ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, agencyLogoPathField.getText()); } } @@ -87,24 +124,87 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { buttonGroup3 = new javax.swing.ButtonGroup(); jScrollPane1 = new javax.swing.JScrollPane(); jPanel1 = new javax.swing.JPanel(); - useBestViewerRB = new javax.swing.JRadioButton(); - keepCurrentViewerRB = new javax.swing.JRadioButton(); - jLabelSelectFile = new javax.swing.JLabel(); - jLabelTimeDisplay = new javax.swing.JLabel(); - useLocalTimeRB = new javax.swing.JRadioButton(); - useGMTTimeRB = new javax.swing.JRadioButton(); - jLabelHideKnownFiles = new javax.swing.JLabel(); - dataSourcesHideKnownCB = new javax.swing.JCheckBox(); - viewsHideKnownCB = new javax.swing.JCheckBox(); - dataSourcesHideSlackCB = new javax.swing.JCheckBox(); - viewsHideSlackCB = new javax.swing.JCheckBox(); - jLabelHideSlackFiles = new javax.swing.JLabel(); + logoPanel = new javax.swing.JPanel(); agencyLogoImageLabel = new javax.swing.JLabel(); agencyLogoPathField = new javax.swing.JTextField(); browseLogosButton = new javax.swing.JButton(); + agencyLogoPreview = new javax.swing.JLabel(); + viewPanel = new javax.swing.JPanel(); + jLabelSelectFile = new javax.swing.JLabel(); + useBestViewerRB = new javax.swing.JRadioButton(); + keepCurrentViewerRB = new javax.swing.JRadioButton(); + jLabelHideKnownFiles = new javax.swing.JLabel(); + dataSourcesHideKnownCB = new javax.swing.JCheckBox(); + viewsHideKnownCB = new javax.swing.JCheckBox(); + jLabelHideSlackFiles = new javax.swing.JLabel(); + dataSourcesHideSlackCB = new javax.swing.JCheckBox(); + viewsHideSlackCB = new javax.swing.JCheckBox(); + jLabelTimeDisplay = new javax.swing.JLabel(); + useLocalTimeRB = new javax.swing.JRadioButton(); + useGMTTimeRB = new javax.swing.JRadioButton(); jScrollPane1.setBorder(null); + logoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.logoPanel.border.title"))); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(agencyLogoImageLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoImageLabel.text")); // NOI18N + + agencyLogoPathField.setEditable(false); + agencyLogoPathField.setBackground(new java.awt.Color(255, 255, 255)); + agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N + agencyLogoPathField.setFocusable(false); + agencyLogoPathField.setRequestFocusEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(browseLogosButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.browseLogosButton.text")); // NOI18N + browseLogosButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseLogosButtonActionPerformed(evt); + } + }); + + agencyLogoPreview.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + org.openide.awt.Mnemonics.setLocalizedText(agencyLogoPreview, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPreview.text")); // NOI18N + agencyLogoPreview.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + agencyLogoPreview.setMaximumSize(new java.awt.Dimension(64, 64)); + agencyLogoPreview.setMinimumSize(new java.awt.Dimension(64, 64)); + agencyLogoPreview.setPreferredSize(new java.awt.Dimension(64, 64)); + + javax.swing.GroupLayout logoPanelLayout = new javax.swing.GroupLayout(logoPanel); + logoPanel.setLayout(logoPanelLayout); + logoPanelLayout.setHorizontalGroup( + logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, logoPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(agencyLogoImageLabel) + .addGroup(logoPanelLayout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(agencyLogoPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseLogosButton))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(agencyLogoPreview, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(149, Short.MAX_VALUE)) + ); + logoPanelLayout.setVerticalGroup( + logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(logoPanelLayout.createSequentialGroup() + .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(agencyLogoPreview, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(logoPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(agencyLogoImageLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(agencyLogoPathField) + .addComponent(browseLogosButton)))) + .addGap(0, 0, 0)) + ); + + viewPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewPanel.border.title"))); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectFile, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelSelectFile.text")); // NOI18N + buttonGroup1.add(useBestViewerRB); org.openide.awt.Mnemonics.setLocalizedText(useBestViewerRB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.text")); // NOI18N useBestViewerRB.setToolTipText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.toolTipText")); // NOI18N @@ -123,7 +223,37 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectFile, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelSelectFile.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabelHideKnownFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideKnownFiles.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideKnownCB.text")); // NOI18N + dataSourcesHideKnownCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + dataSourcesHideKnownCBActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(viewsHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideKnownCB.text")); // NOI18N + viewsHideKnownCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + viewsHideKnownCBActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideSlackCB.text")); // NOI18N + dataSourcesHideSlackCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + dataSourcesHideSlackCBActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(viewsHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideSlackCB.text")); // NOI18N + viewsHideSlackCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + viewsHideSlackCBActionPerformed(evt); + } + }); org.openide.awt.Mnemonics.setLocalizedText(jLabelTimeDisplay, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelTimeDisplay.text")); // NOI18N @@ -143,93 +273,34 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabelHideKnownFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideKnownFiles.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideKnownCB.text")); // NOI18N - dataSourcesHideKnownCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - dataSourcesHideKnownCBActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(viewsHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideKnownCB.text")); // NOI18N - viewsHideKnownCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - viewsHideKnownCBActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideSlackCB.text")); // NOI18N - dataSourcesHideSlackCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - dataSourcesHideSlackCBActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(viewsHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideSlackCB.text")); // NOI18N - viewsHideSlackCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - viewsHideSlackCBActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(agencyLogoImageLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoImageLabel.text")); // NOI18N - - agencyLogoPathField.setEditable(false); - agencyLogoPathField.setBackground(new java.awt.Color(255, 255, 255)); - agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N - agencyLogoPathField.setFocusable(false); - agencyLogoPathField.setRequestFocusEnabled(false); - - org.openide.awt.Mnemonics.setLocalizedText(browseLogosButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.browseLogosButton.text")); // NOI18N - browseLogosButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseLogosButtonActionPerformed(evt); - } - }); - - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() + javax.swing.GroupLayout viewPanelLayout = new javax.swing.GroupLayout(viewPanel); + viewPanel.setLayout(viewPanelLayout); + viewPanelLayout.setHorizontalGroup( + viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup() .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabelTimeDisplay) - .addComponent(jLabelHideKnownFiles) - .addComponent(jLabelSelectFile) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(10, 10, 10) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(useLocalTimeRB) - .addComponent(useGMTTimeRB) - .addComponent(keepCurrentViewerRB) - .addComponent(useBestViewerRB) - .addComponent(dataSourcesHideKnownCB) - .addComponent(viewsHideKnownCB)))) - .addContainerGap(140, Short.MAX_VALUE)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabelHideSlackFiles) - .addComponent(agencyLogoImageLabel) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(10, 10, 10) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(agencyLogoPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(browseLogosButton)) - .addComponent(dataSourcesHideSlackCB) - .addComponent(viewsHideSlackCB)))) - .addGap(0, 0, Short.MAX_VALUE)))) + .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(viewPanelLayout.createSequentialGroup() + .addGap(10, 10, 10) + .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(useGMTTimeRB) + .addComponent(keepCurrentViewerRB) + .addComponent(useBestViewerRB) + .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(useLocalTimeRB) + .addComponent(dataSourcesHideSlackCB) + .addComponent(viewsHideSlackCB) + .addComponent(dataSourcesHideKnownCB) + .addComponent(viewsHideKnownCB)))) + .addComponent(jLabelHideSlackFiles) + .addComponent(jLabelTimeDisplay) + .addComponent(jLabelHideKnownFiles) + .addComponent(jLabelSelectFile)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() + viewPanelLayout.setVerticalGroup( + viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup() .addContainerGap() .addComponent(jLabelSelectFile) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -253,14 +324,28 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(useLocalTimeRB) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(useGMTTimeRB) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(agencyLogoImageLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(agencyLogoPathField) - .addComponent(browseLogosButton)) - .addGap(35, 35, 35)) + .addComponent(useGMTTimeRB)) + ); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(viewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(viewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(logoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) ); jScrollPane1.setViewportView(jPanel1); @@ -269,11 +354,15 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 672, Short.MAX_VALUE) + .addGap(0, 0, 0)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1) + .addGroup(layout.createSequentialGroup() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 489, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -310,17 +399,32 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { }//GEN-LAST:event_viewsHideSlackCBActionPerformed private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed + String oldLogoPath = agencyLogoPathField.getText(); int returnState = fc.showOpenDialog(this); if (returnState == JFileChooser.APPROVE_OPTION) { String path = fc.getSelectedFile().getPath(); - agencyLogoPathField.setText(path); - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + try { + updateAgencyLogo(path); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } catch (IOException | IndexOutOfBoundsException ex) { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(this.getClass(), + "AutopsyOptionsPanel.invalidImageFile.msg"), + NbBundle.getMessage(this.getClass(), "AutopsyOptionsPanel.invalidImageFile.title"), + JOptionPane.ERROR_MESSAGE); + try { + updateAgencyLogo(oldLogoPath); //restore previous setting if new one is invalid + } catch (IOException ex1) { + logger.log(Level.WARNING, "Error loading image from previously saved agency logo path", ex1); + } + } } }//GEN-LAST:event_browseLogosButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel agencyLogoImageLabel; private javax.swing.JTextField agencyLogoPathField; + private javax.swing.JLabel agencyLogoPreview; private javax.swing.JButton browseLogosButton; private javax.swing.ButtonGroup buttonGroup1; private javax.swing.ButtonGroup buttonGroup3; @@ -333,9 +437,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JRadioButton keepCurrentViewerRB; + private javax.swing.JPanel logoPanel; private javax.swing.JRadioButton useBestViewerRB; private javax.swing.JRadioButton useGMTTimeRB; private javax.swing.JRadioButton useLocalTimeRB; + private javax.swing.JPanel viewPanel; private javax.swing.JCheckBox viewsHideKnownCB; private javax.swing.JCheckBox viewsHideSlackCB; // End of variables declaration//GEN-END:variables diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 5ac6cbd626..26a2cc03e0 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -1,7 +1,7 @@ CTL_DataContentAction=DataContent CTL_DataContentTopComponent=Data Content CTL_CustomAboutAction=About -OptionsCategory_Name_General=View +OptionsCategory_Name_General=Application OptionsCategory_Keywords_General=Autopsy Options HINT_DataContentTopComponent=This is a DataContent window HINT_NodeTableTopComponent=This is a DataResult window @@ -198,7 +198,6 @@ AutopsyOptionsPanel.agencyLogoPathField.text= SortChooserDialog.label=remove SortChooser.addCriteriaButton.text=Add Sort Criteria DataResultViewerThumbnail.sortButton.text=Sort - CriterionChooser.ascendingRadio.text=\u25b2 Ascending\n CriterionChooser.removeButton.text=Remove CriterionChooser.descendingRadio.text=\u25bc Descending From 3d306b31baa5966db98acd6ecaacd572a7d0edc2 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 28 Nov 2017 16:30:32 -0500 Subject: [PATCH 29/34] 3158 fix NPE when some invalid image files are tried as agency logo --- .../sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java index 4862846b13..435bdc99b4 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java @@ -85,6 +85,9 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel { File file = new File(agencyLogoPathField.getText()); if (file.exists()) { BufferedImage image = ImageIO.read(file); //create it as an image first to support BMP files + if (image == null) { + throw new IOException("Unable to read file as a BufferedImage for file " + file.toString()); + } agencyLogoIcon = new ImageIcon(image.getScaledInstance(64, 64, 4)); agencyLogoPreview.setText(""); } From 2d9c20b90c8753200db3139afab8d85b73db0535 Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 29 Nov 2017 12:39:36 -0500 Subject: [PATCH 30/34] Modified EmbeddedFileExtractor to use Tika for OOXML files. FileTypeDetector needed to be updated to use TikaInputStream because a new version of Apache Compress was pulled in with tika-parsers. --- Core/ivy.xml | 1 + Core/nbproject/project.properties | 8 +- Core/nbproject/project.xml | 149 +++--- .../EmbeddedFileExtractorIngestModule.java | 12 +- ... => MSOfficeEmbeddedContentExtractor.java} | 499 ++++++++---------- .../modules/filetypeid/FileTypeDetector.java | 22 +- 6 files changed, 315 insertions(+), 376 deletions(-) rename Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/{ImageExtractor.java => MSOfficeEmbeddedContentExtractor.java} (58%) diff --git a/Core/ivy.xml b/Core/ivy.xml index b6cfe4a568..eea67feb19 100755 --- a/Core/ivy.xml +++ b/Core/ivy.xml @@ -16,6 +16,7 @@ + diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 8868378570..7c36c61db7 100755 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -1,10 +1,13 @@ file.reference.activemq-all-5.11.1.jar=release/modules/ext/activemq-all-5.11.1.jar file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar +file.reference.commons-compress-1.12.jar=release/modules/ext/commons-compress-1.12.jar +file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar +file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar -file.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1.jar +file.reference.metadata-extractor-2.9.1.jar=release/modules/ext/metadata-extractor-2.9.1.jar file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar @@ -13,6 +16,7 @@ file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar file.reference.sqlite-jdbc-3.8.11.jar=release/modules/ext/sqlite-jdbc-3.8.11.jar file.reference.StixLib.jar=release/modules/ext/StixLib.jar file.reference.tika-core-1.14.jar=release/modules/ext/tika-core-1.14.jar +file.reference.tika-parsers-1.14.jar=release/modules/ext/tika-parsers-1.14.jar file.reference.Tsk_DataModel_PostgreSQL.jar=release/modules/ext/Tsk_DataModel_PostgreSQL.jar file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar @@ -21,12 +25,10 @@ file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8 file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial -javadoc.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip license.file=../LICENSE-2.0.txt nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true -source.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip!/Source/ source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar spec.version.base=10.9 diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 0e6b98892f..525e6da6a7 100755 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -307,7 +307,6 @@ org.sleuthkit.autopsy.datasourceprocessors org.sleuthkit.autopsy.directorytree org.sleuthkit.autopsy.events - org.sleuthkit.autopsy.externalresults org.sleuthkit.autopsy.filesearch org.sleuthkit.autopsy.guiutils org.sleuthkit.autopsy.ingest @@ -321,93 +320,25 @@ org.sleuthkit.autopsy.report org.sleuthkit.datamodel + + ext/zookeeper-3.4.6.jar + release/modules/ext/zookeeper-3.4.6.jar + ext/jdom-2.0.5.jar release/modules/ext/jdom-2.0.5.jar - - ext/postgresql-9.4.1211.jre7.jar - release/modules/ext/postgresql-9.4.1211.jre7.jar - - - ext/mchange-commons-java-0.2.9.jar - release/modules/ext/mchange-commons-java-0.2.9.jar - - - ext/c3p0-0.9.5.jar - release/modules/ext/c3p0-0.9.5.jar - - - ext/xmpcore-5.1.2.jar - release/modules/ext/xmpcore-5.1.2.jar - - - ext/StixLib.jar - release/modules/ext/StixLib.jar - - - ext/sqlite-jdbc-3.8.11.jar - release/modules/ext/sqlite-jdbc-3.8.11.jar - - - ext/opencv-248.jar - release/modules/ext/opencv-248.jar - - - ext/Rejistry-1.0-SNAPSHOT.jar - release/modules/ext/Rejistry-1.0-SNAPSHOT.jar - - - ext/activemq-all-5.11.1.jar - release/modules/ext/activemq-all-5.11.1.jar - - - ext/Rejistry-1.0-SNAPSHOT.jar - release/modules/ext/Rejistry-1.0-SNAPSHOT.jar - - - ext/jython-standalone-2.7.0.jar - release/modules/ext/jython-standalone-2.7.0.jar - - - ext/sevenzipjbinding.jar - release/modules/ext/sevenzipjbinding.jar - - - ext/sevenzipjbinding-AllPlatforms.jar - release/modules/ext/sevenzipjbinding-AllPlatforms.jar - ext/tika-core-1.14.jar release/modules/ext/tika-core-1.14.jar - - ext/metadata-extractor-2.8.1.jar - release/modules/ext/metadata-extractor-2.8.1.jar - - - ext/metadata-extractor-2.8.1.jar - release/modules/ext/metadata-extractor-2.8.1.jar - - - ext/jdom-2.0.5-contrib.jar - release/modules/ext/jdom-2.0.5-contrib.jar - ext/Tsk_DataModel_PostgreSQL.jar release/modules/ext/Tsk_DataModel_PostgreSQL.jar - ext/zookeeper-3.4.6.jar - release/modules/ext/zookeeper-3.4.6.jar - - - ext/curator-client-2.8.0.jar - release/modules/ext/curator-client-2.8.0.jar - - - ext/curator-recipes-2.8.0.jar - release/modules/ext/curator-recipes-2.8.0.jar + ext/opencv-248.jar + release/modules/ext/opencv-248.jar ext/curator-framework-2.8.0.jar @@ -417,10 +348,78 @@ ext/commons-dbcp2-2.1.1.jar release\modules\ext\commons-dbcp2-2.1.1.jar + + ext/tika-parsers-1.14.jar + release/modules/ext/tika-parsers-1.14.jar + + + ext/jython-standalone-2.7.0.jar + release/modules/ext/jython-standalone-2.7.0.jar + + + ext/sevenzipjbinding.jar + release/modules/ext/sevenzipjbinding.jar + + + ext/mchange-commons-java-0.2.9.jar + release/modules/ext/mchange-commons-java-0.2.9.jar + + + ext/postgresql-9.4.1211.jre7.jar + release/modules/ext/postgresql-9.4.1211.jre7.jar + + + ext/curator-recipes-2.8.0.jar + release/modules/ext/curator-recipes-2.8.0.jar + + + ext/xmpcore-5.1.2.jar + release/modules/ext/xmpcore-5.1.2.jar + + + ext/StixLib.jar + release/modules/ext/StixLib.jar + + + ext/curator-client-2.8.0.jar + release/modules/ext/curator-client-2.8.0.jar + + + ext/sqlite-jdbc-3.8.11.jar + release/modules/ext/sqlite-jdbc-3.8.11.jar + + + ext/activemq-all-5.11.1.jar + release/modules/ext/activemq-all-5.11.1.jar + + + ext/Rejistry-1.0-SNAPSHOT.jar + release/modules/ext/Rejistry-1.0-SNAPSHOT.jar + + + ext/sevenzipjbinding-AllPlatforms.jar + release/modules/ext/sevenzipjbinding-AllPlatforms.jar + ext/commons-pool2-2.4.2.jar release\modules\ext\commons-pool2-2.4.2.jar + + ext/metadata-extractor-2.9.1.jar + release/modules/ext/metadata-extractor-2.9.1.jar + + + ext/commons-compress-1.12.jar + release/modules/ext/commons-compress-1.12.jar + + + ext/jdom-2.0.5-contrib.jar + release/modules/ext/jdom-2.0.5-contrib.jar + + + ext/c3p0-0.9.5.jar + release/modules/ext/c3p0-0.9.5.jar + diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java index 7d4328da59..7a9d9b04ef 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2017 Basis Technology Corp. + * Copyright 2015 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,7 +44,7 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"}; NON-NLS private String moduleDirRelative; private String moduleDirAbsolute; - private ImageExtractor imageExtractor; + private MSOfficeEmbeddedContentExtractor officeExtractor; private SevenZipExtractor archiveExtractor; private FileTypeDetector fileTypeDetector; @@ -98,10 +98,10 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda } /* - * Construct an embedded images extractor for processing Microsoft + * Construct an embedded content extractor for processing Microsoft * Office documents. */ - this.imageExtractor = new ImageExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); + this.officeExtractor = new MSOfficeEmbeddedContentExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); } @Override @@ -134,8 +134,8 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda */ if (archiveExtractor.isSevenZipExtractionSupported(abstractFile)) { archiveExtractor.unpack(abstractFile); - } else if (imageExtractor.isImageExtractionSupported(abstractFile)) { - imageExtractor.extractImage(abstractFile); + } else if (officeExtractor.isContentExtractionSupported(abstractFile)) { + officeExtractor.extractEmbeddedContent(abstractFile); } return ProcessResult.OK; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java similarity index 58% rename from Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java rename to Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java index d58d935e97..668b8cfcdf 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2015 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,14 +21,16 @@ package org.sleuthkit.autopsy.modules.embeddedfileextractor; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.lang.IllegalArgumentException; -import java.lang.IndexOutOfBoundsException; -import java.lang.NullPointerException; +import java.io.InputStream; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.logging.Level; -import org.apache.poi.POIXMLException; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; import org.apache.poi.hwpf.usermodel.Picture; import org.apache.poi.hslf.usermodel.HSLFPictureData; import org.apache.poi.hslf.usermodel.HSLFSlideShow; @@ -39,11 +41,18 @@ import org.apache.poi.hwpf.model.PicturesTable; import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.util.RecordFormatException; -import org.apache.poi.xslf.usermodel.XMLSlideShow; -import org.apache.poi.xslf.usermodel.XSLFPictureData; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import org.apache.poi.xwpf.usermodel.XWPFDocument; -import org.apache.poi.xwpf.usermodel.XWPFPictureData; +import org.apache.tika.config.TikaConfig; +import org.apache.tika.detect.Detector; +import org.apache.tika.exception.TikaException; +import org.apache.tika.extractor.EmbeddedDocumentExtractor; +import org.apache.tika.extractor.ParsingEmbeddedDocumentExtractor; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.mime.MediaType; +import org.apache.tika.mime.MimeTypeException; +import org.apache.tika.parser.AutoDetectParser; +import org.apache.tika.parser.ParseContext; +import org.apache.tika.parser.Parser; +import org.apache.tika.sax.BodyContentHandler; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -57,24 +66,34 @@ import org.sleuthkit.datamodel.EncodedFileOutputStream; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; -class ImageExtractor { +/** + * Extracts embedded content (e.g. images, audio, video) from Microsoft Office + * documents (both original and OOXML forms). + */ +class MSOfficeEmbeddedContentExtractor { private final FileManager fileManager; private final IngestServices services; - private static final Logger logger = Logger.getLogger(ImageExtractor.class.getName()); + private static final Logger LOGGER = Logger.getLogger(MSOfficeEmbeddedContentExtractor.class.getName()); private final IngestJobContext context; private String parentFileName; - private final String UNKNOWN_NAME_PREFIX = "image_"; //NON-NLS + private final String UNKNOWN_IMAGE_NAME_PREFIX = "image_"; //NON-NLS private final FileTypeDetector fileTypeDetector; private String moduleDirRelative; private String moduleDirAbsolute; + private AutoDetectParser parser = new AutoDetectParser(); + private Detector detector = parser.getDetector(); + private TikaConfig config = TikaConfig.getDefaultConfig(); + /** - * Enum of mimetypes which support image extraction + * Enum of mimetypes for which we can extract embedded content. */ - enum SupportedImageExtractionFormats { + enum SupportedExtractionFormats { DOC("application/msword"), //NON-NLS DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), //NON-NLS @@ -85,7 +104,7 @@ class ImageExtractor { private final String mimeType; - SupportedImageExtractionFormats(final String mimeType) { + SupportedExtractionFormats(final String mimeType) { this.mimeType = mimeType; } @@ -93,11 +112,10 @@ class ImageExtractor { public String toString() { return this.mimeType; } - // TODO Expand to support more formats } - private SupportedImageExtractionFormats abstractFileExtractionFormat; + private SupportedExtractionFormats abstractFileExtractionFormat; - ImageExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) { + MSOfficeEmbeddedContentExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) { this.fileManager = Case.getCurrentCase().getServices().getFileManager(); this.services = IngestServices.getInstance(); @@ -111,15 +129,15 @@ class ImageExtractor { * This method returns true if the file format is currently supported. Else * it returns false. Performs only Apache Tika based detection. * - * @param abstractFile The AbstractFilw whose mimetype is to be determined. + * @param abstractFile The AbstractFile whose mimetype is to be determined. * * @return This method returns true if the file format is currently * supported. Else it returns false. */ - boolean isImageExtractionSupported(AbstractFile abstractFile) { + boolean isContentExtractionSupported(AbstractFile abstractFile) { try { String abstractFileMimeType = fileTypeDetector.getFileType(abstractFile); - for (SupportedImageExtractionFormats s : SupportedImageExtractionFormats.values()) { + for (SupportedExtractionFormats s : SupportedExtractionFormats.values()) { if (s.toString().equals(abstractFileMimeType)) { abstractFileExtractionFormat = s; return true; @@ -127,60 +145,55 @@ class ImageExtractor { } return false; } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error executing FileTypeDetector.getFileType()", ex); // NON-NLS + LOGGER.log(Level.SEVERE, "Error executing FileTypeDetector.getFileType()", ex); // NON-NLS return false; } } /** - * This method selects the appropriate process of extracting images from - * files using POI classes. Once the images have been extracted, the method - * adds them to the DB and fires a ModuleContentEvent. ModuleContent Event - * is not fired if the no images were extracted from the processed file. + * This method selects the appropriate process of extracting embedded + * content from files using either Tika or POI classes. Once the content has + * been extracted as files, the method adds them to the DB and fires a + * ModuleContentEvent. ModuleContent Event is not fired if no content + * was extracted from the processed file. * - * @param format * @param abstractFile The abstract file to be processed. */ - void extractImage(AbstractFile abstractFile) { - // - // switchcase for different supported formats - // process abstractFile according to the format by calling appropriate methods. - - List listOfExtractedImages = null; + void extractEmbeddedContent(AbstractFile abstractFile) { + List listOfExtractedImages = null; List listOfExtractedImageAbstractFiles = null; this.parentFileName = EmbeddedFileExtractorIngestModule.getUniqueName(abstractFile); - //check if already has derived files, skip + + // Skip files that already have been unpacked. try { if (abstractFile.hasChildren()) { //check if local unpacked dir exists if (new File(getOutputFolderPath(parentFileName)).exists()) { - logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName()); //NON-NLS + LOGGER.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName()); //NON-NLS return; } } } catch (TskCoreException e) { - logger.log(Level.SEVERE, String.format("Error checking if file already has been processed, skipping: %s", parentFileName), e); //NON-NLS + LOGGER.log(Level.SEVERE, String.format("Error checking if file already has been processed, skipping: %s", parentFileName), e); //NON-NLS return; } + + // Call the appropriate extraction method based on mime type switch (abstractFileExtractionFormat) { - case DOC: - listOfExtractedImages = extractImagesFromDoc(abstractFile); - break; case DOCX: - listOfExtractedImages = extractImagesFromDocx(abstractFile); + case PPTX: + case XLSX: + listOfExtractedImages = extractEmbeddedContentFromOOXML(abstractFile); + break; + case DOC: + listOfExtractedImages = extractEmbeddedImagesFromDoc(abstractFile); break; case PPT: - listOfExtractedImages = extractImagesFromPpt(abstractFile); - break; - case PPTX: - listOfExtractedImages = extractImagesFromPptx(abstractFile); + listOfExtractedImages = extractEmbeddedImagesFromPpt(abstractFile); break; case XLS: listOfExtractedImages = extractImagesFromXls(abstractFile); break; - case XLSX: - listOfExtractedImages = extractImagesFromXlsx(abstractFile); - break; default: break; } @@ -190,13 +203,13 @@ class ImageExtractor { } // the common task of adding abstractFile to derivedfiles is performed. listOfExtractedImageAbstractFiles = new ArrayList<>(); - for (ExtractedImage extractedImage : listOfExtractedImages) { + for (ExtractedFile extractedImage : listOfExtractedImages) { try { listOfExtractedImageAbstractFiles.add(fileManager.addDerivedFile(extractedImage.getFileName(), extractedImage.getLocalPath(), extractedImage.getSize(), extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(), true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1)); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS + LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS } } if (!listOfExtractedImages.isEmpty()) { @@ -206,43 +219,79 @@ class ImageExtractor { } /** - * Extract images from doc format files. + * Extracts embedded content from OOXML documents (i.e. pptx, docx and xlsx) + * using Tika. This will extract images and other multimedia content + * embedded in the given file. + * + * @param abstractFile The file to extract content from. + * + * @return A list of extracted files. + */ + private List extractEmbeddedContentFromOOXML(AbstractFile abstractFile) { + Metadata metadata = new Metadata(); + + ParseContext parseContext = new ParseContext(); + parseContext.set(Parser.class, parser); + + // Passing -1 to the BodyContentHandler constructor disables the Tika + // write limit (which defaults to 100,000 characters. + ContentHandler contentHandler = new BodyContentHandler(-1); + + // TODO: this will be needed once we upgrade to Tika 1.16 or later. + // OfficeParserConfig officeParserConfig = new OfficeParserConfig(); + // officeParserConfig.setUseSAXPptxExtractor(true); + // officeParserConfig.setUseSAXDocxExtractor(true); + // parseContext.set(OfficeParserConfig.class, officeParserConfig); + EmbeddedDocumentExtractor extractor = new EmbeddedContentExtractor(parseContext); + parseContext.set(EmbeddedDocumentExtractor.class, extractor); + ReadContentInputStream stream = new ReadContentInputStream(abstractFile); + + try { + parser.parse(stream, contentHandler, metadata, parseContext); + } catch (IOException | SAXException | TikaException ex) { + LOGGER.log(Level.WARNING, "Error while parsing file, skipping: " + abstractFile.getName(), ex); //NON-NLS + return null; + } + + return ((EmbeddedContentExtractor) extractor).getExtractedImages(); + } + + /** + * Extract embedded images from doc format files. * * @param af the file from which images are to be extracted. * * @return list of extracted images. Returns null in case no images were * extracted. */ - private List extractImagesFromDoc(AbstractFile af) { + private List extractEmbeddedImagesFromDoc(AbstractFile af) { List listOfAllPictures; - + try { HWPFDocument doc = new HWPFDocument(new ReadContentInputStream(af)); PicturesTable pictureTable = doc.getPicturesTable(); listOfAllPictures = pictureTable.getAllPictures(); - } catch (IOException | IllegalArgumentException | - IndexOutOfBoundsException | NullPointerException ex) { + } catch (IOException | IllegalArgumentException + | IndexOutOfBoundsException | NullPointerException ex) { // IOException: // Thrown when the document has issues being read. - + // IllegalArgumentException: // This will catch OldFileFormatException, which is thrown when the // document's format is Word 95 or older. Alternatively, this is // thrown when attempting to load an RTF file as a DOC file. // However, our code verifies the file format before ever running it - // through the ImageExtractor. This exception gets thrown in the + // through the EmbeddedContentExtractor. This exception gets thrown in the // "IN10-0137.E01" image regardless. The reason is unknown. - // IndexOutOfBoundsException: // NullPointerException: // These get thrown in certain images. The reason is unknown. It is // likely due to problems with the file formats that POI is poorly // handling. - return null; } catch (Throwable ex) { // instantiating POI containers throw RuntimeExceptions - logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS + LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS return null; } @@ -255,7 +304,7 @@ class ImageExtractor { if (outputFolderPath == null) { return null; } - List listOfExtractedImages = new ArrayList<>(); + List listOfExtractedImages = new ArrayList<>(); byte[] data = null; for (Picture picture : listOfAllPictures) { String fileName = picture.suggestFullFileName(); @@ -266,99 +315,43 @@ class ImageExtractor { } writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data); // TODO Extract more info from the Picture viz ctime, crtime, atime, mtime - listOfExtractedImages.add(new ExtractedImage(fileName, getFileRelativePath(fileName), picture.getSize(), af)); + listOfExtractedImages.add(new ExtractedFile(fileName, getFileRelativePath(fileName), picture.getSize())); } return listOfExtractedImages; } /** - * Extract images from docx format files. + * Extract embedded images from ppt format files. * * @param af the file from which images are to be extracted. * * @return list of extracted images. Returns null in case no images were * extracted. */ - private List extractImagesFromDocx(AbstractFile af) { - List listOfAllPictures = null; - - try { - XWPFDocument docx = new XWPFDocument(new ReadContentInputStream(af)); - listOfAllPictures = docx.getAllPictures(); - } catch (POIXMLException | IOException ex) { - // POIXMLException: - // Thrown when document fails to load - - // IOException: - // Thrown when the document has issues being read. - - return null; - } catch (Throwable ex) { - // instantiating POI containers throw RuntimeExceptions - logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName()), ex); //NON-NLS - return null; - } - - // if no images are extracted from the PPT, return null, else initialize - // the output folder for image extraction. - String outputFolderPath; - if (listOfAllPictures.isEmpty()) { - return null; - } else { - outputFolderPath = getOutputFolderPath(this.parentFileName); - } - if (outputFolderPath == null) { - return null; - } - List listOfExtractedImages = new ArrayList<>(); - byte[] data = null; - for (XWPFPictureData xwpfPicture : listOfAllPictures) { - String fileName = xwpfPicture.getFileName(); - try { - data = xwpfPicture.getData(); - } catch (Exception ex) { - return null; - } - writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data); - listOfExtractedImages.add(new ExtractedImage(fileName, getFileRelativePath(fileName), xwpfPicture.getData().length, af)); - } - return listOfExtractedImages; - } - - /** - * Extract images from ppt format files. - * - * @param af the file from which images are to be extracted. - * - * @return list of extracted images. Returns null in case no images were - * extracted. - */ - private List extractImagesFromPpt(AbstractFile af) { + private List extractEmbeddedImagesFromPpt(AbstractFile af) { List listOfAllPictures = null; - + try { HSLFSlideShow ppt = new HSLFSlideShow(new ReadContentInputStream(af)); listOfAllPictures = ppt.getPictureData(); - } catch (IOException | IllegalArgumentException | - IndexOutOfBoundsException ex) { + } catch (IOException | IllegalArgumentException + | IndexOutOfBoundsException ex) { // IllegalArgumentException: // This will catch OldFileFormatException, which is thrown when the // document version is unsupported. The IllegalArgumentException may // also get thrown for unknown reasons. - + // IOException: // Thrown when the document has issues being read. - // IndexOutOfBoundsException: // This gets thrown in certain images. The reason is unknown. It is // likely due to problems with the file formats that POI is poorly // handling. - return null; } catch (Throwable ex) { // instantiating POI containers throw RuntimeExceptions - logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS + LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS return null; } @@ -374,10 +367,10 @@ class ImageExtractor { return null; } - // extract the images to the above initialized outputFolder. + // extract the content to the above initialized outputFolder. // extraction path - outputFolder/image_number.ext int i = 0; - List listOfExtractedImages = new ArrayList<>(); + List listOfExtractedImages = new ArrayList<>(); byte[] data = null; for (HSLFPictureData pictureData : listOfAllPictures) { @@ -404,80 +397,19 @@ class ImageExtractor { default: continue; } - String imageName = UNKNOWN_NAME_PREFIX + i + ext; //NON-NLS + String imageName = UNKNOWN_IMAGE_NAME_PREFIX + i + ext; //NON-NLS try { data = pictureData.getData(); } catch (Exception ex) { return null; } writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data); - listOfExtractedImages.add(new ExtractedImage(imageName, getFileRelativePath(imageName), pictureData.getData().length, af)); + listOfExtractedImages.add(new ExtractedFile(imageName, getFileRelativePath(imageName), pictureData.getData().length)); i++; } return listOfExtractedImages; } - /** - * Extract images from pptx format files. - * - * @param af the file from which images are to be extracted. - * - * @return list of extracted images. Returns null in case no images were - * extracted. - */ - private List extractImagesFromPptx(AbstractFile af) { - List listOfAllPictures = null; - - try { - XMLSlideShow pptx = new XMLSlideShow(new ReadContentInputStream(af)); - listOfAllPictures = pptx.getPictureData(); - } catch (POIXMLException | IOException ex) { - // POIXMLException: - // Thrown when document fails to load. - - // IOException: - // Thrown when the document has issues being read - - return null; - } catch (Throwable ex) { - // instantiating POI containers throw RuntimeExceptions - logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName()), ex); //NON-NLS - return null; - } - - // if no images are extracted from the PPT, return null, else initialize - // the output folder for image extraction. - String outputFolderPath; - if (listOfAllPictures.isEmpty()) { - return null; - } else { - outputFolderPath = getOutputFolderPath(this.parentFileName); - } - if (outputFolderPath == null) { - return null; - } - - List listOfExtractedImages = new ArrayList<>(); - byte[] data = null; - for (XSLFPictureData xslsPicture : listOfAllPictures) { - - // get image file name, write it to the module outputFolder, and add - // it to the listOfExtractedImageAbstractFiles. - String fileName = xslsPicture.getFileName(); - try { - data = xslsPicture.getData(); - } catch (Exception ex) { - return null; - } - writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data); - listOfExtractedImages.add(new ExtractedImage(fileName, getFileRelativePath(fileName), xslsPicture.getData().length, af)); - - } - - return listOfExtractedImages; - - } - /** * Extract images from xls format files. * @@ -486,41 +418,37 @@ class ImageExtractor { * @return list of extracted images. Returns null in case no images were * extracted. */ - private List extractImagesFromXls(AbstractFile af) { + private List extractImagesFromXls(AbstractFile af) { List listOfAllPictures = null; - + try { Workbook xls = new HSSFWorkbook(new ReadContentInputStream(af)); listOfAllPictures = xls.getAllPictures(); - } catch (IOException | LeftoverDataException | - RecordFormatException | IllegalArgumentException | - IndexOutOfBoundsException ex) { + } catch (IOException | LeftoverDataException + | RecordFormatException | IllegalArgumentException + | IndexOutOfBoundsException ex) { // IllegalArgumentException: // This will catch OldFileFormatException, which is thrown when the // document version is unsupported. The IllegalArgumentException may // also get thrown for unknown reasons. - + // IOException: // Thrown when the document has issues being read. - // LeftoverDataException: // This is thrown for poorly formatted files that have more data // than expected. - // RecordFormatException: // This is thrown for poorly formatted files that have less data // that expected. - // IllegalArgumentException: // IndexOutOfBoundsException: // These get thrown in certain images. The reason is unknown. It is // likely due to problems with the file formats that POI is poorly // handling. - return null; } catch (Throwable ex) { // instantiating POI containers throw RuntimeExceptions - logger.log(Level.SEVERE, String.format("%s%s", NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()), af.getName()), ex); //NON-NLS + LOGGER.log(Level.SEVERE, String.format("%s%s", NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()), af.getName()), ex); //NON-NLS return null; } @@ -537,75 +465,17 @@ class ImageExtractor { } int i = 0; - List listOfExtractedImages = new ArrayList<>(); + List listOfExtractedImages = new ArrayList<>(); byte[] data = null; for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) { - String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS + String imageName = UNKNOWN_IMAGE_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS try { data = pictureData.getData(); } catch (Exception ex) { return null; } writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data); - listOfExtractedImages.add(new ExtractedImage(imageName, getFileRelativePath(imageName), pictureData.getData().length, af)); - i++; - } - return listOfExtractedImages; - - } - - /** - * Extract images from xlsx format files. - * - * @param af the file from which images are to be extracted. - * - * @return list of extracted images. Returns null in case no images were - * extracted. - */ - private List extractImagesFromXlsx(AbstractFile af) { - List listOfAllPictures = null; - - try { - Workbook xlsx = new XSSFWorkbook(new ReadContentInputStream(af)); - listOfAllPictures = xlsx.getAllPictures(); - } catch (POIXMLException | IOException ex) { - // POIXMLException: - // Thrown when document fails to load. - - // IOException: - // Thrown when the document has issues being read - - return null; - } catch (Throwable ex) { - // instantiating POI containers throw RuntimeExceptions - logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName()), ex); //NON-NLS - return null; - } - - // if no images are extracted from the PPT, return null, else initialize - // the output folder for image extraction. - String outputFolderPath; - if (listOfAllPictures.isEmpty()) { - return null; - } else { - outputFolderPath = getOutputFolderPath(this.parentFileName); - } - if (outputFolderPath == null) { - return null; - } - - int i = 0; - List listOfExtractedImages = new ArrayList<>(); - byte[] data = null; - for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) { - String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); - try { - data = pictureData.getData(); - } catch (Exception ex) { - return null; - } - writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data); - listOfExtractedImages.add(new ExtractedImage(imageName, getFileRelativePath(imageName), pictureData.getData().length, af)); + listOfExtractedImages.add(new ExtractedFile(imageName, getFileRelativePath(imageName), pictureData.getData().length)); i++; } return listOfExtractedImages; @@ -623,18 +493,17 @@ class ImageExtractor { try (EncodedFileOutputStream fos = new EncodedFileOutputStream(new FileOutputStream(outputPath), TskData.EncodingType.XOR1)) { fos.write(data); } catch (IOException ex) { - logger.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS + LOGGER.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS } } /** - * Gets path to the output folder for image extraction. If the path does not + * Gets path to the output folder for file extraction. If the path does not * exist, it is created. * - * @param parentFileName name of the abstract file being processed for image - * extraction. + * @param parentFileName name of the abstract file being processed * - * @return path to the image extraction folder for a given abstract file. + * @return path to the file extraction folder for a given abstract file. */ private String getOutputFolderPath(String parentFileName) { String outputFolderPath = moduleDirAbsolute + File.separator + parentFileName; @@ -643,7 +512,7 @@ class ImageExtractor { try { outputFilePath.mkdirs(); } catch (SecurityException ex) { - logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg", parentFileName), ex); + LOGGER.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg", parentFileName), ex); return null; } } @@ -665,11 +534,11 @@ class ImageExtractor { } /** - * Represents the image extracted using POI methods. Currently, POI is not - * capable of extracting ctime, crtime, mtime, and atime; these values are - * set to 0. + * Represents a file extracted using either Tika or POI methods. Currently, + * POI is not capable of extracting ctime, crtime, mtime, and atime; these + * values are set to 0. */ - private static class ExtractedImage { + private static class ExtractedFile { //String fileName, String localPath, long size, long ctime, long crtime, //long atime, long mtime, boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails @@ -680,13 +549,12 @@ class ImageExtractor { private final long crtime; private final long atime; private final long mtime; - private final AbstractFile parentFile; - ExtractedImage(String fileName, String localPath, long size, AbstractFile parentFile) { - this(fileName, localPath, size, 0, 0, 0, 0, parentFile); + ExtractedFile(String fileName, String localPath, long size) { + this(fileName, localPath, size, 0, 0, 0, 0); } - ExtractedImage(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, AbstractFile parentFile) { + ExtractedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime) { this.fileName = fileName; this.localPath = localPath; this.size = size; @@ -694,7 +562,6 @@ class ImageExtractor { this.crtime = crtime; this.atime = atime; this.mtime = mtime; - this.parentFile = parentFile; } public String getFileName() { @@ -724,9 +591,83 @@ class ImageExtractor { public long getMtime() { return mtime; } + } - public AbstractFile getParentFile() { - return parentFile; + /** + * Our custom embedded content extractor for OOXML files. We pass an + * instance of this class to Tika and Tika calls the parseEmbedded() method + * when it encounters an embedded file. + */ + private class EmbeddedContentExtractor extends ParsingEmbeddedDocumentExtractor { + + private int fileCount = 0; + // Map of file name to ExtractedFile instance. This can revert to a + // plain old list after we upgrade to Tika 1.16 or above. + private final Map nameToExtractedFileMap = new HashMap<>(); + + public EmbeddedContentExtractor(ParseContext context) { + super(context); + } + + @Override + public boolean shouldParseEmbedded(Metadata metadata) { + return true; + } + + @Override + public void parseEmbedded(InputStream stream, ContentHandler handler, + Metadata metadata, boolean outputHtml) throws SAXException, IOException { + + // Get the mime type for the embedded document + MediaType contentType = detector.detect(stream, metadata); + + if (!contentType.getType().equalsIgnoreCase("image") //NON-NLS + && !contentType.getType().equalsIgnoreCase("video") //NON-NLS + && !contentType.getType().equalsIgnoreCase("application") //NON-NLS + && !contentType.getType().equalsIgnoreCase("audio")) { //NON-NLS + return; + } + + // try to get the name of the embedded file from the metadata + String name = metadata.get(Metadata.RESOURCE_NAME_KEY); + + // TODO: This can be removed after we upgrade to Tika 1.16 or + // above. The 1.16 version of Tika keeps track of files that + // have been seen before. + if (nameToExtractedFileMap.containsKey(name)) { + return; + } + + if (name == null) { + name = UNKNOWN_IMAGE_NAME_PREFIX + fileCount++; + } else { + //make sure to select only the file name (not any directory paths + //that might be included in the name) and make sure + //to normalize the name + name = FilenameUtils.normalize(FilenameUtils.getName(name)); + } + + // Get the suggested extension based on mime type. + if (name.indexOf('.') == -1) { + try { + name += config.getMimeRepository().forName(contentType.toString()).getExtension(); + } catch (MimeTypeException ex) { + LOGGER.log(Level.WARNING, "Failed to get suggested extension for the following type: " + contentType.toString(), ex); //NON-NLS + } + } + + File extractedFile = new File(Paths.get(getOutputFolderPath(parentFileName), name).toString()); + writeExtractedImage(extractedFile.getAbsolutePath(), IOUtils.toByteArray(stream)); + nameToExtractedFileMap.put(name, new ExtractedFile(name, getFileRelativePath(name), FileUtils.sizeOf(extractedFile))); + } + + /** + * Get list of extracted files. + * + * @return List of extracted files. + */ + public List getExtractedImages() { + return new ArrayList<>(nameToExtractedFileMap.values()); } } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index 4bfbb8b734..b1aff14a8f 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -27,7 +28,9 @@ import java.util.TreeSet; import java.util.logging.Level; import java.util.stream.Collectors; import org.apache.tika.Tika; +import org.apache.tika.io.TikaInputStream; import org.apache.tika.mime.MimeTypes; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; @@ -36,6 +39,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -50,8 +54,6 @@ public class FileTypeDetector { private static final Logger logger = Logger.getLogger(FileTypeDetector.class.getName()); private static final Tika tika = new Tika(); - private static final int BUFFER_SIZE = 64 * 1024; - private final byte buffer[] = new byte[BUFFER_SIZE]; private final List userDefinedFileTypes; private final List autopsyDefinedFileTypes; private static SortedSet tikaDetectedTypes; @@ -270,17 +272,11 @@ public class FileTypeDetector { * bytes to Tika. */ if (null == mimeType) { - try { - byte buf[]; - int len = file.read(buffer, 0, BUFFER_SIZE); - if (len < BUFFER_SIZE) { - buf = new byte[len]; - System.arraycopy(buffer, 0, buf, 0, len); - } else { - buf = buffer; - } - String tikaType = tika.detect(buf, file.getName()); - + ReadContentInputStream stream = new ReadContentInputStream(file); + + try (TikaInputStream tikaInputStream = TikaInputStream.get(stream)) { + String tikaType = tika.detect(tikaInputStream, file.getName()); + /* * Remove the Tika suffix from the MIME type name. */ From f495a42db8862aa5dd023635f60f2cb248674cd4 Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 29 Nov 2017 14:29:12 -0500 Subject: [PATCH 31/34] Fix for extracted file sizes. --- .../MSOfficeEmbeddedContentExtractor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java index 668b8cfcdf..61376d31f1 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java @@ -657,8 +657,9 @@ class MSOfficeEmbeddedContentExtractor { } File extractedFile = new File(Paths.get(getOutputFolderPath(parentFileName), name).toString()); - writeExtractedImage(extractedFile.getAbsolutePath(), IOUtils.toByteArray(stream)); - nameToExtractedFileMap.put(name, new ExtractedFile(name, getFileRelativePath(name), FileUtils.sizeOf(extractedFile))); + byte[] fileData = IOUtils.toByteArray(stream); + writeExtractedImage(extractedFile.getAbsolutePath(), fileData); + nameToExtractedFileMap.put(name, new ExtractedFile(name, getFileRelativePath(name), fileData.length)); } /** From 77cf4a0ebb930b93af74e5e8777167c454835512 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 29 Nov 2017 16:34:18 -0500 Subject: [PATCH 32/34] Encryption Detection settings panel implemented. --- .../encryptiondetection/Bundle.properties | 7 + .../EncryptionDetectionFileIngestModule.java | 57 ++++-- .../EncryptionDetectionIngestJobSettings.java | 133 ++++++++++++ ...yptionDetectionIngestJobSettingsPanel.form | 119 +++++++++++ ...yptionDetectionIngestJobSettingsPanel.java | 193 ++++++++++++++++++ .../EncryptionDetectionModuleFactory.java | 57 +++++- 6 files changed, 539 insertions(+), 27 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties create mode 100755 Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettings.java create mode 100755 Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form create mode 100755 Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties new file mode 100755 index 0000000000..3d8238e173 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties @@ -0,0 +1,7 @@ +EncryptionDetectionIngestJobSettingsPanel.minimumEntropyLabel.text=Minimum Entropy: +EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeLabel.text=Minimum File Size: +EncryptionDetectionIngestJobSettingsPanel.fileSizeMultiplesEnforcedCheckbox.text=Consider only files with sizes that are multiples of 512. +EncryptionDetectionIngestJobSettingsPanel.slackFilesAllowedCheckbox.text=Consider slack space files. +EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text= +EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text= +EncryptionDetectionIngestJobSettingsPanel.mbLabel.text=MB diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java index f18911c016..15fccb6a74 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java @@ -45,8 +45,11 @@ import org.sleuthkit.datamodel.TskData; */ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter { - private static final double ENTROPY_THRESHOLD = 7.5; - private static final int FILE_SIZE_THRESHOLD = 5242880; // 5MB + static final double DEFAULT_CONFIG_MINIMUM_ENTROPY = 7.5; + static final int DEFAULT_CONFIG_MINIMUM_FILE_SIZE = 5242880; // 5MB; + static final boolean DEFAULT_CONFIG_FILE_SIZE_MULTIPLE_ENFORCED = true; + static final boolean DEFAULT_CONFIG_SLACK_FILES_ALLOWED = true; + private static final int FILE_SIZE_MODULUS = 512; private static final double ONE_OVER_LOG2 = 1.4426950408889634073599246810019; // (1 / log(2)) private static final int BYTE_OCCURENCES_BUFFER_SIZE = 256; @@ -55,13 +58,24 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter private final Logger LOGGER = SERVICES.getLogger(EncryptionDetectionModuleFactory.getModuleName()); private FileTypeDetector fileTypeDetector; private Blackboard blackboard; - private double entropy; + private double calculatedEntropy; + + private final double minimumEntropy; + private final int minimumFileSize; + private final boolean fileSizeMultipleEnforced; + private final boolean slackFilesAllowed; /** - * Create a EncryptionDetectionFileIngestModule object that will detect files - * that are encrypted and create blackboard artifacts as appropriate. + * Create a EncryptionDetectionFileIngestModule object that will detect + * files that are encrypted and create blackboard artifacts as appropriate. + * The supplied EncryptionDetectionIngestJobSettings object is used to + * configure the module. */ - EncryptionDetectionFileIngestModule() { + EncryptionDetectionFileIngestModule(EncryptionDetectionIngestJobSettings settings) { + minimumEntropy = settings.getMinimumEntropy(); + minimumFileSize = settings.getMinimumFileSize(); + fileSizeMultipleEnforced = settings.isFileSizeMultipleEnforced(); + slackFilesAllowed = settings.isSlackFilesAllowed(); } @Override @@ -120,7 +134,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter */ StringBuilder detailsSb = new StringBuilder(); detailsSb.append("File: ").append(file.getParentPath()).append(file.getName()).append("
\n"); - detailsSb.append("Entropy: ").append(entropy); + detailsSb.append("Entropy: ").append(calculatedEntropy); SERVICES.postMessage(IngestMessage.createDataMessage(EncryptionDetectionModuleFactory.getModuleName(), "Encryption Detected Match: " + file.getName(), @@ -159,7 +173,8 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter if (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR) - && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR)) { + && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR) + && (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || slackFilesAllowed)) { /* * Qualify the file against hash databases. */ @@ -168,17 +183,19 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter * Qualify the size. */ long contentSize = file.getSize(); - if (contentSize >= FILE_SIZE_THRESHOLD && (contentSize % FILE_SIZE_MODULUS) == 0) { - /* - * Qualify the MIME type. - */ - try { - String mimeType = fileTypeDetector.getFileType(file); - if (mimeType != null && mimeType.equals("application/octet-stream")) { - possiblyEncrypted = true; + if (contentSize >= minimumFileSize) { + if (!fileSizeMultipleEnforced || (contentSize % FILE_SIZE_MODULUS) == 0) { + /* + * Qualify the MIME type. + */ + try { + String mimeType = fileTypeDetector.getFileType(file); + if (mimeType != null && mimeType.equals("application/octet-stream")) { + possiblyEncrypted = true; + } + } catch (TskCoreException ex) { + throw new TskCoreException("Failed to detect the file type.", ex); } - } catch (TskCoreException ex) { - throw new TskCoreException("Failed to detect the file type.", ex); } } } @@ -186,8 +203,8 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter if (possiblyEncrypted) { try { - entropy = calculateEntropy(file); - if (entropy > ENTROPY_THRESHOLD) { + calculatedEntropy = calculateEntropy(file); + if (calculatedEntropy >= minimumEntropy) { return true; } } catch (IOException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettings.java new file mode 100755 index 0000000000..2aa6ad860d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettings.java @@ -0,0 +1,133 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.modules.encryptiondetection; + +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; + +/** + * Ingest job settings for the Encryption Detection module. + */ +final class EncryptionDetectionIngestJobSettings implements IngestModuleIngestJobSettings { + + private static final long serialVersionUID = 1L; + + private double minimumEntropy; + private int minimumFileSize; + private boolean fileSizeMultipleEnforced; + private boolean slackFilesAllowed; + + /** + * Instantiate the ingest job settings with default values. + */ + EncryptionDetectionIngestJobSettings() { + this.minimumEntropy = EncryptionDetectionFileIngestModule.DEFAULT_CONFIG_MINIMUM_ENTROPY; + this.minimumFileSize = EncryptionDetectionFileIngestModule.DEFAULT_CONFIG_MINIMUM_FILE_SIZE; + this.fileSizeMultipleEnforced = EncryptionDetectionFileIngestModule.DEFAULT_CONFIG_FILE_SIZE_MULTIPLE_ENFORCED; + this.slackFilesAllowed = EncryptionDetectionFileIngestModule.DEFAULT_CONFIG_SLACK_FILES_ALLOWED; + } + + /** + * Instantiate the ingest job settings. + * + * @param minimumEntropy The minimum entropy. + * @param minimumFileSize The minimum file size. + * @param fileSizeMultipleEnforced Files must be a multiple of 512 to be + * processed. + * @param slackFilesAllowed Slack files can be processed. + */ + EncryptionDetectionIngestJobSettings(double minimumEntropy, int minimumFileSize, boolean fileSizeMultipleEnforced, boolean slackFilesAllowed) { + this.minimumEntropy = minimumEntropy; + this.minimumFileSize = minimumFileSize; + this.fileSizeMultipleEnforced = fileSizeMultipleEnforced; + this.slackFilesAllowed = slackFilesAllowed; + } + + @Override + public long getVersionNumber() { + return serialVersionUID; + } + + /** + * Get the minimum entropy necessary for the creation of blackboard + * artifacts. + * + * @return The minimum entropy. + */ + double getMinimumEntropy() { + return minimumEntropy; + } + + /** + * Set the minimum entropy necessary for the creation of blackboard + * artifacts. + */ + void setMinimumEntropy(double minimumEntropy) { + this.minimumEntropy = minimumEntropy; + } + + /** + * Get the minimum file size necessary for the creation of blackboard + * artifacts. + * + * @return The minimum file size. + */ + int getMinimumFileSize() { + return minimumFileSize; + } + + /** + * Set the minimum file size necessary for the creation of blackboard + * artifacts. + */ + void setMinimumFileSize(int minimumFileSize) { + this.minimumFileSize = minimumFileSize; + } + + /** + * Is the file size multiple enforced? + * + * @return True if enforcement is enabled; otherwise false. + */ + boolean isFileSizeMultipleEnforced() { + return fileSizeMultipleEnforced; + } + + /** + * Enable or disable file size multiple enforcement. + */ + void setFileSizeMultipleEnforced(boolean fileSizeMultipleEnforced) { + this.fileSizeMultipleEnforced = fileSizeMultipleEnforced; + } + + /** + * Are slack files allowed for processing? + * + * @return True if slack files are allowed; otherwise false. + */ + boolean isSlackFilesAllowed() { + return slackFilesAllowed; + } + + /** + * Allow or disallow slack files for processing. + */ + void setSlackFilesAllowed(boolean slackFilesAllowed) { + this.slackFilesAllowed = slackFilesAllowed; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form new file mode 100755 index 0000000000..cb231c8abb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form @@ -0,0 +1,119 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java new file mode 100755 index 0000000000..c1c72852d7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java @@ -0,0 +1,193 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.modules.encryptiondetection; + +import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; + +/** + * Ingest job settings panel for the Encryption Detection module. + */ +final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel { + + private static final int MEGABYTE_SIZE = 1048576; + private static final double MINIMUM_ENTROPY_INPUT_RANGE_MIN = 6.0; + private static final double MINIMUM_ENTROPY_INPUT_RANGE_MAX = 8.0; + private static final int MINIMUM_FILE_SIZE_INPUT_RANGE_MIN = 1; + + /** + * Instantiate the ingest job settings panel. + * + * @param settings The ingest job settings. + */ + public EncryptionDetectionIngestJobSettingsPanel(EncryptionDetectionIngestJobSettings settings) { + initComponents(); + customizeComponents(settings); + } + + /** + * Update components with values from the ingest job settings. + * + * @param settings The ingest job settings. + */ + private void customizeComponents(EncryptionDetectionIngestJobSettings settings) { + minimumEntropyTextbox.setText(String.valueOf(settings.getMinimumEntropy())); + minimumFileSizeTextbox.setText(String.valueOf(settings.getMinimumFileSize() / MEGABYTE_SIZE)); + fileSizeMultiplesEnforcedCheckbox.setSelected(settings.isFileSizeMultipleEnforced()); + slackFilesAllowedCheckbox.setSelected(settings.isSlackFilesAllowed()); + } + + @Override + public IngestModuleIngestJobSettings getSettings() { + validateMinimumEntropy(); + validateMinimumFileSize(); + + return new EncryptionDetectionIngestJobSettings( + Double.valueOf(minimumEntropyTextbox.getText()), + Integer.valueOf(minimumFileSizeTextbox.getText()) * MEGABYTE_SIZE, + fileSizeMultiplesEnforcedCheckbox.isSelected(), + slackFilesAllowedCheckbox.isSelected()); + } + + /** + * Validate the minimum entropy input. + * + * @throws IllegalArgumentException If the input is empty, invalid, or out + * of range. + */ + @Messages({ + "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyInput.validationError.text=Minimum entropy input must be a number between 6.0 and 8.0." + }) + private void validateMinimumEntropy() throws IllegalArgumentException { + try { + double minimumEntropy = Double.valueOf(minimumEntropyTextbox.getText()); + if (minimumEntropy < MINIMUM_ENTROPY_INPUT_RANGE_MIN || minimumEntropy > MINIMUM_ENTROPY_INPUT_RANGE_MAX) { + throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyInput.validationError.text")); + } + } catch (NumberFormatException ex) { + throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyInput.validationError.text")); + } + } + + /** + * Validate the minimum file size input. + * + * @throws IllegalArgumentException If the input is empty, invalid, or out + * of range. + */ + @Messages({ + "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeInput.validationError.text=Minimum file size input must be an integer (in megabytes) of 1 or greater." + }) + private void validateMinimumFileSize() throws IllegalArgumentException { + try { + int minimumFileSize = Integer.valueOf(minimumFileSizeTextbox.getText()); + if (minimumFileSize < MINIMUM_FILE_SIZE_INPUT_RANGE_MIN) { + throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeInput.validationError.text")); + } + } catch (NumberFormatException ex) { + throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeInput.validationError.text")); + } + } + + /** + * 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() { + + minimumEntropyTextbox = new javax.swing.JTextField(); + minimumFileSizeTextbox = new javax.swing.JTextField(); + fileSizeMultiplesEnforcedCheckbox = new javax.swing.JCheckBox(); + slackFilesAllowedCheckbox = new javax.swing.JCheckBox(); + minimumEntropyLabel = new javax.swing.JLabel(); + minimumFileSizeLabel = new javax.swing.JLabel(); + mbLabel = new javax.swing.JLabel(); + + minimumEntropyTextbox.setText(org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text")); // NOI18N + + minimumFileSizeTextbox.setText(org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(fileSizeMultiplesEnforcedCheckbox, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.fileSizeMultiplesEnforcedCheckbox.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(slackFilesAllowedCheckbox, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.slackFilesAllowedCheckbox.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(minimumEntropyLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(minimumFileSizeLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(mbLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.mbLabel.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(minimumFileSizeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(minimumFileSizeTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(minimumEntropyLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(mbLabel)) + .addComponent(fileSizeMultiplesEnforcedCheckbox) + .addComponent(slackFilesAllowedCheckbox)) + .addContainerGap(15, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(minimumEntropyLabel) + .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(minimumFileSizeLabel) + .addComponent(minimumFileSizeTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(mbLabel)) + .addGap(15, 15, 15) + .addComponent(fileSizeMultiplesEnforcedCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(slackFilesAllowedCheckbox) + .addContainerGap(182, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JCheckBox fileSizeMultiplesEnforcedCheckbox; + private javax.swing.JLabel mbLabel; + private javax.swing.JLabel minimumEntropyLabel; + private javax.swing.JTextField minimumEntropyTextbox; + private javax.swing.JLabel minimumFileSizeLabel; + private javax.swing.JTextField minimumFileSizeTextbox; + private javax.swing.JCheckBox slackFilesAllowedCheckbox; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java index 53eca1aec6..27549f648f 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java @@ -22,10 +22,12 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.IngestModuleFactory; -import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; +import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; /** * A factory that creates file ingest modules that detect encryption. @@ -33,9 +35,9 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; @ServiceProvider(service = IngestModuleFactory.class) @Messages({ "EncryptionDetectionFileIngestModule.moduleName.text=Encryption Detection", - "EncryptionDetectionFileIngestModule.getDesc.text=Looks for large files with high entropy." + "EncryptionDetectionFileIngestModule.getDesc.text=Looks for files with the specified minimum entropy." }) -public class EncryptionDetectionModuleFactory extends IngestModuleFactoryAdapter { +public class EncryptionDetectionModuleFactory implements IngestModuleFactory { @Override public String getModuleDisplayName() { @@ -44,7 +46,7 @@ public class EncryptionDetectionModuleFactory extends IngestModuleFactoryAdapter /** * Get the name of the module. - * + * * @return The module name. */ static String getModuleName() { @@ -67,7 +69,48 @@ public class EncryptionDetectionModuleFactory extends IngestModuleFactoryAdapter } @Override - public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) { - return new EncryptionDetectionFileIngestModule(); + public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { + if (!(settings instanceof EncryptionDetectionIngestJobSettings)) { + throw new IllegalArgumentException("Expected settings argument to be an instance of EncryptionDetectionIngestJobSettings."); + } + return new EncryptionDetectionFileIngestModule((EncryptionDetectionIngestJobSettings) settings); } -} \ No newline at end of file + + @Override + public boolean hasGlobalSettingsPanel() { + return false; + } + + @Override + public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() { + throw new UnsupportedOperationException(); + } + + @Override + public IngestModuleIngestJobSettings getDefaultIngestJobSettings() { + return new EncryptionDetectionIngestJobSettings(); + } + + @Override + public boolean hasIngestJobSettingsPanel() { + return true; + } + + @Override + public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) { + if (!(settings instanceof EncryptionDetectionIngestJobSettings)) { + throw new IllegalArgumentException("Expected settings argument to be an instance of EncryptionDetectionIngestJobSettings"); + } + return new EncryptionDetectionIngestJobSettingsPanel((EncryptionDetectionIngestJobSettings) settings); + } + + @Override + public boolean isDataSourceIngestModuleFactory() { + return false; + } + + @Override + public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings settings) { + throw new UnsupportedOperationException(); + } +} From 50223cc0c97c756eae4639819d00ce5773f33080 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 29 Nov 2017 17:30:09 -0500 Subject: [PATCH 33/34] Revised the settings panel. --- .../encryptiondetection/Bundle.properties | 1 + ...yptionDetectionIngestJobSettingsPanel.form | 56 ++++++++++++------- ...yptionDetectionIngestJobSettingsPanel.java | 51 ++++++++++------- 3 files changed, 69 insertions(+), 39 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties index 3d8238e173..fdc7d9ed0d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties @@ -5,3 +5,4 @@ EncryptionDetectionIngestJobSettingsPanel.slackFilesAllowedCheckbox.text=Conside EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text= EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text= EncryptionDetectionIngestJobSettingsPanel.mbLabel.text=MB +EncryptionDetectionIngestJobSettingsPanel.detectionSettingsLabel.text=Detection Settings diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form index cb231c8abb..99b6034502 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form @@ -19,26 +19,32 @@ + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - + @@ -46,21 +52,23 @@ + + - + - + - + - + @@ -115,5 +123,15 @@
+ + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java index c1c72852d7..8a8576c15b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java @@ -123,6 +123,7 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest minimumEntropyLabel = new javax.swing.JLabel(); minimumFileSizeLabel = new javax.swing.JLabel(); mbLabel = new javax.swing.JLabel(); + detectionSettingsLabel = new javax.swing.JLabel(); minimumEntropyTextbox.setText(org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text")); // NOI18N @@ -138,6 +139,9 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest org.openide.awt.Mnemonics.setLocalizedText(mbLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.mbLabel.text")); // NOI18N + detectionSettingsLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(detectionSettingsLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.detectionSettingsLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -145,43 +149,50 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(detectionSettingsLabel) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(minimumFileSizeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(minimumFileSizeTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(minimumEntropyLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(mbLabel)) - .addComponent(fileSizeMultiplesEnforcedCheckbox) - .addComponent(slackFilesAllowedCheckbox)) - .addContainerGap(15, Short.MAX_VALUE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(fileSizeMultiplesEnforcedCheckbox) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(minimumFileSizeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(minimumFileSizeTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(minimumEntropyLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(mbLabel)) + .addComponent(slackFilesAllowedCheckbox)))) + .addContainerGap(17, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() + .addComponent(detectionSettingsLabel) + .addGap(16, 16, 16) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(minimumEntropyLabel) - .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(minimumEntropyLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(minimumFileSizeLabel) .addComponent(minimumFileSizeTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(mbLabel)) - .addGap(15, 15, 15) + .addComponent(mbLabel) + .addComponent(minimumFileSizeLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(fileSizeMultiplesEnforcedCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(slackFilesAllowedCheckbox) - .addContainerGap(182, Short.MAX_VALUE)) + .addContainerGap(160, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel detectionSettingsLabel; private javax.swing.JCheckBox fileSizeMultiplesEnforcedCheckbox; private javax.swing.JLabel mbLabel; private javax.swing.JLabel minimumEntropyLabel; From 42111e272cf7a6f532aa58891ae8177f7807cbd1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 30 Nov 2017 10:29:38 -0500 Subject: [PATCH 34/34] Minor tweak to settings panel. --- ...yptionDetectionIngestJobSettingsPanel.form | 39 ++++++++----------- ...yptionDetectionIngestJobSettingsPanel.java | 31 +++++++-------- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form index 99b6034502..26c859fe4d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form @@ -16,35 +16,30 @@ - + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - + + + - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java index 8a8576c15b..123a62ec85 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java @@ -149,25 +149,22 @@ final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngest .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(slackFilesAllowedCheckbox) .addComponent(detectionSettingsLabel) .addGroup(layout.createSequentialGroup() - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(fileSizeMultiplesEnforcedCheckbox) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addComponent(minimumFileSizeLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(minimumFileSizeTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(minimumEntropyLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(mbLabel)) - .addComponent(slackFilesAllowedCheckbox)))) - .addContainerGap(17, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(minimumFileSizeLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(minimumFileSizeTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(minimumEntropyLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(mbLabel)) + .addComponent(fileSizeMultiplesEnforcedCheckbox)) + .addContainerGap(15, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)