Merge pull request #2365 from millmanorama/841-maintain-selection

841 maintain selection
This commit is contained in:
Richard Cordovano 2016-10-05 12:38:48 -04:00 committed by GitHub
commit 5e9d3b7082
64 changed files with 3478 additions and 2140 deletions

View File

@ -222,6 +222,10 @@
</dependency>
</module-dependencies>
<public-packages>
<package>net.sf.sevenzipjbinding</package>
<package>net.sf.sevenzipjbinding.impl</package>
<package>net.sf.sevenzipjbinding.simple</package>
<package>net.sf.sevenzipjbinding.simple.impl</package>
<package>org.sleuthkit.autopsy.actions</package>
<package>org.sleuthkit.autopsy.casemodule</package>
<package>org.sleuthkit.autopsy.casemodule.events</package>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-15 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,8 +19,8 @@
package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.JMenu;
@ -39,6 +39,7 @@ import org.sleuthkit.datamodel.TskCoreException;
*/
abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
private static final long serialVersionUID = 1L;
private static final String NO_COMMENT = "";
AddTagAction(String menuText) {
@ -82,15 +83,16 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
// to be reworked.
private class TagMenu extends JMenu {
private static final long serialVersionUID = 1L;
TagMenu() {
super(getActionDisplayName());
// Get the current set of tag names.
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<TagName> tagNames = null;
Map<String, TagName> tagNamesMap = null;
try {
tagNames = tagsManager.getAllTagNames();
Collections.sort(tagNames);
tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap());
} catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
}
@ -102,11 +104,11 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
// Each tag name in the current set of tags gets its own menu item in
// the "Quick Tags" sub-menu. Selecting one of these menu items adds
// a tag with the associated tag name.
if (null != tagNames && !tagNames.isEmpty()) {
for (final TagName tagName : tagNames) {
JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName());
if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
JMenuItem tagNameItem = new JMenuItem(entry.getKey());
tagNameItem.addActionListener((ActionEvent e) -> {
addTag(tagName, NO_COMMENT);
getAndAddTag(entry.getKey(), entry.getValue(), NO_COMMENT);
});
quickTagMenu.add(tagNameItem);
}
@ -114,7 +116,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();
@ -143,5 +145,30 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
});
add(tagAndCommentItem);
}
/**
* 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.
*
* @param tagDisplayName display name for the tag name
* @param tagName TagName object associated with the tag name,
* may be null
* @param comment comment for the content or artifact tag
*/
private void getAndAddTag(String tagDisplayName, TagName tagName, String comment) {
if (tagName == null) {
try {
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
} catch (TagsManager.TagNameAlreadyExistsException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database.", ex); //NON-NLS
} catch (TskCoreException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS
}
}
addTag(tagName, comment);
}
}
}

View File

@ -1,10 +1,10 @@
GetTagNameDialog.tagNameField.text=
GetTagNameDialog.cancelButton.text=Cancel
GetTagNameDialog.okButton.text=OK
GetTagNameDialog.preexistingLabel.text=Pre-existing Tags:
GetTagNameDialog.preexistingLabel.text=Pre-existing Tag Names:
GetTagNameDialog.newTagPanel.border.title=New Tag
GetTagNameDialog.tagNameLabel.text=Tag Name:
GetTagNameAndCommentDialog.newTagButton.text=New Tag
GetTagNameAndCommentDialog.newTagButton.text=New Tag Name
GetTagNameAndCommentDialog.okButton.text=OK
GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
GetTagNameAndCommentDialog.commentText.text=
@ -42,7 +42,7 @@ GetTagNameDialog.createTag=Create Tag
GetTagNameDialog.cancelName=Cancel
GetTagNameDialog.mustSupplyTtagName.msg=Must supply a tag name to continue.
GetTagNameDialog.tagNameErr=Tag Name
GetTagNameDialog.illegalChars.msg=The tag name contains illegal characters.\nCannot contain any of the following symbols\: \\ \: * ? " < > |
GetTagNameDialog.illegalChars.msg=The tag name contains illegal characters.\nCannot contain any of the following symbols\: \\ \: * ? " < > | , ;
GetTagNameDialog.illegalCharsErr=Illegal Characters
GetTagNameDialog.unableToAddTagNameToCase.msg=Unable to add the {0} tag name to the case.
GetTagNameDialog.taggingErr=Tagging Error
@ -58,4 +58,4 @@ OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder
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
CTL_OpenPythonModulesFolderAction=Python Plugins

View File

@ -28,7 +28,7 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="newTagButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="78" max="32767" attributes="0"/>
<EmptySpace pref="48" max="32767" attributes="0"/>
<Component id="okButton" linkSize="1" min="-2" pref="67" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/>

View File

@ -21,8 +21,8 @@ package org.sleuthkit.autopsy.actions;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
@ -43,7 +43,7 @@ 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 HashMap<String, TagName> tagNames = new HashMap<>();
private final Map<String, TagName> tagNamesMap = new TreeMap<>();
private TagNameAndComment tagNameAndComment = null;
public static class TagNameAndComment {
@ -91,13 +91,18 @@ public class GetTagNameAndCommentDialog extends JDialog {
* dialog.
*/
public static TagNameAndComment doDialog(Window owner) {
return new GetTagNameAndCommentDialog(owner).tagNameAndComment;
GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog(owner);
dialog.display();
return dialog.tagNameAndComment;
}
private GetTagNameAndCommentDialog(Window owner) {
super(owner,
NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.createTag"),
ModalityType.APPLICATION_MODAL);
}
private void display() {
initComponents();
// Set up the dialog to close when Esc is pressed.
@ -106,6 +111,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
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();
@ -114,27 +120,27 @@ public class GetTagNameAndCommentDialog extends JDialog {
// 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.
// Tag name DTOs may be null (user tag names that have not been used do
// not exist in the database).
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<TagName> currentTagNames = null;
try {
currentTagNames = tagsManager.getAllTagNames();
tagNamesMap.putAll(tagsManager.getDisplayNamesToTagNamesMap());
} catch (TskCoreException ex) {
Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
}
if (null != currentTagNames && currentTagNames.isEmpty()) {
if (null != tagNamesMap && tagNamesMap.isEmpty()) {
tagCombo.addItem(NO_TAG_NAMES_MESSAGE);
} else {
for (TagName tagName : currentTagNames) {
tagNames.put(tagName.getDisplayName(), tagName);
tagCombo.addItem(tagName.getDisplayName());
for (String tagDisplayName : tagNamesMap.keySet()) {
tagCombo.addItem(tagDisplayName);
}
}
// Center and show the dialog box.
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
setVisible(true);
this.setLocationRelativeTo(this.getOwner());
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
@ -197,7 +203,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, 78, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 48, Short.MAX_VALUE)
.addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton))
@ -240,7 +246,18 @@ public class GetTagNameAndCommentDialog extends JDialog {
}// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
tagNameAndComment = new TagNameAndComment(tagNames.get((String) tagCombo.getSelectedItem()), commentText.getText());
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) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database.", ex); //NON-NLS
} catch (TskCoreException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS
}
}
tagNameAndComment = new TagNameAndComment(tagNameFromCombo, commentText.getText());
dispose();
}//GEN-LAST:event_okButtonActionPerformed
@ -257,7 +274,7 @@ 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) {
tagNames.put(newTagName.getDisplayName(), newTagName);
tagNamesMap.put(newTagName.getDisplayName(), newTagName);
tagCombo.addItem(newTagName.getDisplayName());
tagCombo.setSelectedItem(newTagName.getDisplayName());
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -22,8 +22,9 @@ import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
@ -44,8 +45,9 @@ import org.sleuthkit.datamodel.TskCoreException;
public class GetTagNameDialog extends JDialog {
private static final long serialVersionUID = 1L;
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
private final HashMap<String, TagName> tagNames = new HashMap<>();
private final Map<String, TagName> tagNamesMap = new TreeMap<>();
private TagName tagName = null;
/**
@ -70,14 +72,19 @@ public class GetTagNameDialog extends JDialog {
* @return a TagName instance selected by the user, or null if the user
* canceled the dialog.
*/
public static TagName doDialog(final Window owner) {
return new GetTagNameDialog(owner).tagName;
public static TagName doDialog(Window owner) {
GetTagNameDialog dialog = new GetTagNameDialog(owner);
dialog.display();
return dialog.tagName;
}
private GetTagNameDialog(final Window owner) {
super(owner,
private GetTagNameDialog(Window owner) {
super(owner,
NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.createTag"),
ModalityType.APPLICATION_MODAL);
}
private void display() {
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
initComponents();
@ -87,6 +94,8 @@ public class GetTagNameDialog extends JDialog {
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) {
cancelButtonActionPerformed(e);
@ -96,56 +105,38 @@ public class GetTagNameDialog extends JDialog {
// Get the current set of tag names and hash them for a speedy lookup in
// case the user chooses an existing tag name from the tag names table.
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<TagName> currentTagNames = null;
try {
currentTagNames = tagsManager.getAllTagNames();
tagNamesMap.putAll(tagsManager.getDisplayNamesToTagNamesMap());
} catch (TskCoreException ex) {
Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
}
if (null != currentTagNames) {
for (TagName name : currentTagNames) {
this.tagNames.put(name.getDisplayName(), name);
}
} else {
currentTagNames = new ArrayList<>();
}
// Populate the tag names table.
tagsTable.setModel(new TagsTableModel(currentTagNames));
tagsTable.setModel(new TagsTableModel(new ArrayList<>(tagNamesMap.keySet())));
tagsTable.setTableHeader(null);
tagsTable.setCellSelectionEnabled(false);
tagsTable.setFocusable(false);
tagsTable.setRowHeight(tagsTable.getRowHeight() + 5);
// Center and show the dialog box.
this.setLocationRelativeTo(owner);
setVisible(true);
this.setLocationRelativeTo(this.getOwner());
setVisible(true);
}
private boolean containsIllegalCharacters(String content) {
return (content.contains("\\")
|| content.contains(":")
|| content.contains("*")
|| content.contains("?")
|| content.contains("\"")
|| content.contains("<")
|| content.contains(">")
|| content.contains("|"));
}
private class TagsTableModel extends AbstractTableModel {
private final ArrayList<TagName> tagNames = new ArrayList<>();
private static final long serialVersionUID = 1L;
private final ArrayList<String> tagDisplayNames = new ArrayList<>();
TagsTableModel(List<TagName> tagNames) {
for (TagName tagName : tagNames) {
this.tagNames.add(tagName);
TagsTableModel(List<String> tagDisplayNames) {
for (String tagDisplayName : tagDisplayNames) {
this.tagDisplayNames.add(tagDisplayName);
}
}
@Override
public int getRowCount() {
return tagNames.size();
return tagDisplayNames.size();
}
@Override
@ -160,7 +151,7 @@ public class GetTagNameDialog extends JDialog {
@Override
public String getValueAt(int rowIndex, int columnIndex) {
return tagNames.get(rowIndex).getDisplayName();
return tagDisplayNames.get(rowIndex);
}
}
@ -305,13 +296,13 @@ public class GetTagNameDialog extends JDialog {
"GetTagNameDialog.mustSupplyTtagName.msg"),
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameErr"),
JOptionPane.ERROR_MESSAGE);
} else if (containsIllegalCharacters(tagDisplayName)) {
} else if (TagsManager.containsIllegalCharacters(tagDisplayName)) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalChars.msg"),
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"),
JOptionPane.ERROR_MESSAGE);
} else {
tagName = tagNames.get(tagDisplayName);
tagName = tagNamesMap.get(tagDisplayName);
if (tagName == null) {
try {
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
@ -326,7 +317,7 @@ public class GetTagNameDialog extends JDialog {
JOptionPane.ERROR_MESSAGE);
tagName = null;
} catch (TagsManager.TagNameAlreadyExistsException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database.", ex); //NON-NLS
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"GetTagNameDialog.tagNameAlreadyDef.msg",

View File

@ -1,9 +1,18 @@
TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} out of content size range (0 - {1})
TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} out of content size range (0 - {1})
TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset
TagsManager.predefTagNames.bookmark.text=Bookmark
TagsManager.addContentTag.noCaseWarning=Failed to publish new content tag event. There is no case open.
TagsManager.deleteContentTag.noCaseWarning=Failed to publish content tag deleted event. There is no case open.
TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackboard artifact tag event. There is no case open.
TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open.
OptionsCategory_Name_TagNamesOptions=Tags
OptionsCategory_TagNames=TagNames
Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0}
NewUserTagNameDialog.title.text=New Tag Name
NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ;
NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name
TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message=The tag name already exists in your settings
TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title=Tag name already exists
NewUserTagNameDialog.JOptionPane.tagNameEmpty.message=The tag name cannot be empty
NewUserTagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name
TagOptionsPanel.tagTypesListLabel.text=Tag Names:
TagOptionsPanel.panelDescriptionLabel.text=Autopsy keeps a list of the tag names you have created in the past. Add more or delete them here.
NewTagNameDialog.okButton.text=OK
NewTagNameDialog.cancelButton.text=Cancel
NewTagNameDialog.tagNameTextField.text=
NewTagNameDialog.newTagNameLabel.text=New Tag Name:
TagOptionsPanel.deleteTagNameButton.text=Delete Tag Name
TagOptionsPanel.newTagNameButton.text=New Tag Name

View File

@ -1,9 +1,2 @@
TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} \u30b3\u30f3\u30c6\u30f3\u30c4\u30b5\u30a4\u30ba\u7bc4\u56f2(0 - {1})\u306e\u5916\u3067\u3059
TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} \u30b3\u30f3\u30c6\u30f3\u30c4\u30b5\u30a4\u30ba\u7bc4\u56f2(0 - {1})\u306e\u5916\u3067\u3059
TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset
TagsManager.predefTagNames.bookmark.text=\u30d6\u30c3\u30af\u30de\u30fc\u30af
TagsManager.addContentTag.noCaseWarning=\u65b0\u3057\u3044\u30bf\u30b0\u30a4\u30d9\u30f3\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002
TagsManager.deleteContentTag.noCaseWarning=\u524a\u9664\u3055\u308c\u305f\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002
TagsManager.addBlackboardArtifactTag.noCaseWarning=\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u65b0\u3057\u3044blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002
TagsManager.deleteBlackboardArtifactTag.noCaseWarning=\u524a\u9664\u3055\u308c\u305f\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u65b0\u3057\u3044blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002
Blackboard.unableToIndexArtifact.error.msg=blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8{0}\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002

View File

@ -27,6 +27,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
import org.sleuthkit.autopsy.ingest.IngestServices;
@ -43,6 +44,7 @@ import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.LocalFilesDataSource;
import org.sleuthkit.datamodel.TskDataException;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.CarvingResult;
import org.sleuthkit.datamodel.TskData;
@ -53,6 +55,7 @@ import org.sleuthkit.datamodel.TskData;
*/
public class FileManager implements Closeable {
private static final Logger LOGGER = Logger.getLogger(FileManager.class.getName());
private SleuthkitCase caseDb;
/**
@ -343,7 +346,7 @@ public class FileManager implements Closeable {
}
return caseDb.addCarvedFiles(carvingResult);
}
/**
* Interface for receiving a notification for each file or directory added
* to the case database by a FileManager add files operation.
@ -427,7 +430,11 @@ public class FileManager implements Closeable {
} catch (TskCoreException ex) {
if (null != trans) {
trans.rollback();
try {
trans.rollback();
} catch (TskCoreException ex2) {
LOGGER.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
}
}
throw ex;
}
@ -506,7 +513,7 @@ public class FileManager implements Closeable {
* @throws TskCoreException If there is a problem completing a database
* operation.
*/
private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile,
private AbstractFile addLocalFile(CaseDbTransaction trans, VirtualDirectory parentDirectory, java.io.File localFile,
TskData.EncodingType encodingType, FileAddProgressUpdater progressUpdater) throws TskCoreException {
if (localFile.isDirectory()) {
/*
@ -542,7 +549,7 @@ public class FileManager implements Closeable {
public synchronized void close() throws IOException {
caseDb = null;
}
/**
* Adds a set of local/logical files and/or directories to the case database
* as data source.
@ -624,7 +631,7 @@ public class FileManager implements Closeable {
}
return caseDb.addCarvedFiles(filesToAdd);
}
/**
* Adds a derived file to the case.
*
@ -652,7 +659,7 @@ public class FileManager implements Closeable {
*
* @throws TskCoreException if there is a problem adding the file to the
* case database.
*
*
* @Deprecated Use the version with explicit EncodingType instead
*/
@Deprecated
@ -663,10 +670,10 @@ public class FileManager implements Closeable {
boolean isFile,
AbstractFile parentFile,
String rederiveDetails, String toolName, String toolVersion, String otherDetails) throws TskCoreException {
return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, parentFile,
return addDerivedFile(fileName, localPath, size, ctime, crtime, atime, mtime, isFile, parentFile,
rederiveDetails, toolName, toolVersion, otherDetails, TskData.EncodingType.NONE);
}
/**
* Adds a file or directory of logical/local files data source to the case
* database, recursively adding the contents of directories.
@ -686,7 +693,7 @@ public class FileManager implements Closeable {
*
* @throws TskCoreException If there is a problem completing a database
* operation.
*
*
* @Deprecated Use the version with explicit EncodingType instead
*/
@Deprecated

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tagNameTextField" pref="220" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="okButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="newTagNameLabel" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="newTagNameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="tagNameTextField" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="50" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="newTagNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="NewTagNameDialog.newTagNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="tagNameTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="NewTagNameDialog.tagNameTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="NewTagNameDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="NewTagNameDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,247 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.services;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.openide.util.NbBundle;
final class NewTagNameDialog extends javax.swing.JDialog {
private static final long serialVersionUID = 1L;
private String userTagDisplayName;
private BUTTON_PRESSED result;
enum BUTTON_PRESSED {
OK, CANCEL;
}
/**
* Creates a new NewUserTagNameDialog dialog.
*/
NewTagNameDialog() {
super(new JFrame(NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.title.text")),
NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.title.text"), true);
initComponents();
this.display();
}
/**
* Sets display settings for the dialog and adds appropriate listeners.
*/
private void display() {
setLayout(new BorderLayout());
/*
* Center the dialog
*/
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
int width = this.getSize().width;
int height = this.getSize().height;
setLocation((screenDimension.width - width) / 2, (screenDimension.height - height) / 2);
/*
* Add a handler for when the dialog window is closed directly.
*/
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
doButtonAction(false);
}
});
/*
* Add a listener to enable the OK button when the text field changes.
*/
tagNameTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
fire();
}
@Override
public void removeUpdate(DocumentEvent e) {
fire();
}
@Override
public void insertUpdate(DocumentEvent e) {
fire();
}
private void fire() {
enableOkButton();
}
});
enableOkButton();
/*
* Used to show the dialog.
*/
setResizable(false);
setVisible(true);
}
/**
* Called when a button is pressed or when the dialog is closed.
* @param okPressed whether the OK button was pressed.
*/
private void doButtonAction(boolean okPressed) {
if (okPressed) {
String newTagDisplayName = tagNameTextField.getText().trim();
if (newTagDisplayName.isEmpty()) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameEmpty.message"),
NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameEmpty.title"),
JOptionPane.ERROR_MESSAGE);
return;
}
if (TagsManager.containsIllegalCharacters(newTagDisplayName)) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.message"),
NbBundle.getMessage(NewTagNameDialog.class, "NewUserTagNameDialog.JOptionPane.tagNameIllegalCharacters.title"),
JOptionPane.ERROR_MESSAGE);
return;
}
userTagDisplayName = newTagDisplayName;
result = BUTTON_PRESSED.OK;
} else {
result = BUTTON_PRESSED.CANCEL;
}
setVisible(false);
}
/**
* Returns the tag name entered by the user.
*
* @return a new user tag name
*/
String getTagName() {
return userTagDisplayName;
}
/**
* Returns information about which button was pressed.
*
* @return BUTTON_PRESSED (OK, CANCEL)
*/
BUTTON_PRESSED getResult() {
return result;
}
/**
* Enable the OK button if the tag name text field is not empty.
* Sets the enter button as default, so user can press enter to activate
* an okButton press and add the tag name.
*/
private void enableOkButton() {
okButton.setEnabled(!tagNameTextField.getText().isEmpty());
getRootPane().setDefaultButton(okButton);
}
/**
* 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
newTagNameLabel = new javax.swing.JLabel();
tagNameTextField = new javax.swing.JTextField();
cancelButton = new javax.swing.JButton();
okButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
org.openide.awt.Mnemonics.setLocalizedText(newTagNameLabel, org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.newTagNameLabel.text")); // NOI18N
tagNameTextField.setText(org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.tagNameTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tagNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 220, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(okButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton))
.addComponent(newTagNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(newTagNameLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tagNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(50, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cancelButton)
.addComponent(okButton))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
doButtonAction(true);
}//GEN-LAST:event_okButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
doButtonAction(false);
}//GEN-LAST:event_cancelButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelButton;
private javax.swing.JLabel newTagNameLabel;
private javax.swing.JButton okButton;
private javax.swing.JTextField tagNameTextField;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,180 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.services;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.TagName;
/**
* A tag name definition consisting of a display name, description and color.
*/
@Immutable
final class TagNameDefiniton implements Comparable<TagNameDefiniton> {
private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS
private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS
private final String displayName;
private final String description;
private final TagName.HTML_COLOR color;
/**
* Constructs a tag name definition consisting of a display name,
* description and color.
*
* @param displayName The display name for the tag name.
* @param description The description for the tag name.
* @param color The color for the tag name.
*/
TagNameDefiniton(String displayName, String description, TagName.HTML_COLOR color) {
this.displayName = displayName;
this.description = description;
this.color = color;
}
/**
* Gets the display name for the tag name.
*
* @return The display name.
*/
String getDisplayName() {
return displayName;
}
/**
* Gets the description for the tag name.
*
* @return The description.
*/
String getDescription() {
return description;
}
/**
* Gets the color for the tag name.
*
* @return The color.
*/
TagName.HTML_COLOR getColor() {
return color;
}
/**
* 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(TagNameDefiniton other) {
return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase());
}
/**
* Returns a hash code value for this tag name definition.
*
* @return The has code.
*/
@Override
public int hashCode() {
int hash = 7;
hash = 83 * hash + Objects.hashCode(this.displayName);
return hash;
}
/**
* Indicates whether some other object is "equal to" this tag name
* definition.
*
* @param obj The object to test for equality.
*
* @return True or false.
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof TagNameDefiniton)) {
return false;
}
TagNameDefiniton thatTagName = (TagNameDefiniton) obj;
return this.getDisplayName().equals(thatTagName.getDisplayName());
}
/**
* A string representation of this tag name definition.
*
* @return The display name of the tag type.
*/
@Override
public String toString() {
return displayName;
}
/**
* @return A string representation of the tag name definition in the format
* that is used by the tags settings file.
*/
private String toSettingsFormat() {
return displayName + "," + description + "," + color.name();
}
/**
* Gets tag name definitions from the tag settings file.
*
* @return A set of tag name definition objects.
*/
static synchronized Set<TagNameDefiniton> getTagNameDefinitions() {
Set<TagNameDefiniton> tagNames = new HashSet<>();
String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY);
if (null != setting && !setting.isEmpty()) {
List<String> tagNameTuples = Arrays.asList(setting.split(";"));
for (String tagNameTuple : tagNameTuples) {
String[] tagNameAttributes = tagNameTuple.split(",");
tagNames.add(new TagNameDefiniton(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.valueOf(tagNameAttributes[2])));
}
}
return tagNames;
}
/**
* Sets the tag name definitions in the tag settings file.
*
* @param tagNames A set of tag name definition objects.
*/
static synchronized void setTagNameDefinitions(Set<TagNameDefiniton> tagNames) {
StringBuilder setting = new StringBuilder();
for (TagNameDefiniton tagName : tagNames) {
if (setting.length() != 0) {
setting.append(";");
}
setting.append(tagName.toSettingsFormat());
}
ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString());
}
}

View File

@ -0,0 +1,204 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jPanel1" alignment="0" pref="778" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jPanel1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[750, 500]"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jSplitPane1" max="32767" attributes="0"/>
<Component id="panelDescriptionLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="panelDescriptionLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jSplitPane1" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="panelDescriptionLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="TagOptionsPanel.panelDescriptionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JSplitPane" name="jSplitPane1">
<Properties>
<Property name="dividerLocation" type="int" value="400"/>
<Property name="dividerSize" type="int" value="1"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="modifyTagTypesListPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="left"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="tagTypesListLabel" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="newTagNameButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="deleteTagNameButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="113" max="32767" attributes="0"/>
</Group>
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="tagTypesListLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="383" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="newTagNameButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deleteTagNameButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="tagTypesListLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="TagOptionsPanel.tagTypesListLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="tagNamesList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
<StringArray count="0"/>
</Property>
<Property name="selectionMode" type="int" value="0"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;org.sleuthkit.autopsy.casemodule.services.TagNameDefiniton&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="newTagNameButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/add-tag.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="TagOptionsPanel.newTagNameButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newTagNameButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="deleteTagNameButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/delete-tag.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="TagOptionsPanel.deleteTagNameButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deleteTagNameButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="tagTypesAdditionalPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="right"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="356" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="456" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,272 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.services;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.datamodel.TagName;
/**
* A panel to allow the user to create and delete custom tag types.
*/
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<TagNameDefiniton> tagTypesListModel;
private Set<TagNameDefiniton> tagTypes;
/**
* Creates new form TagsManagerOptionsPanel
*/
TagOptionsPanel() {
tagTypesListModel = new DefaultListModel<>();
tagTypes = new TreeSet<>(TagNameDefiniton.getTagNameDefinitions());
initComponents();
customizeComponents();
}
private void customizeComponents() {
tagNamesList.setModel(tagTypesListModel);
tagNamesList.addListSelectionListener((ListSelectionEvent event) -> {
enableButtons();
});
}
/**
* 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
panelDescriptionLabel = new javax.swing.JLabel();
jSplitPane1 = new javax.swing.JSplitPane();
modifyTagTypesListPanel = new javax.swing.JPanel();
tagTypesListLabel = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
tagNamesList = new javax.swing.JList<>();
newTagNameButton = new javax.swing.JButton();
deleteTagNameButton = new javax.swing.JButton();
tagTypesAdditionalPanel = new javax.swing.JPanel();
jPanel1.setPreferredSize(new java.awt.Dimension(750, 500));
org.openide.awt.Mnemonics.setLocalizedText(panelDescriptionLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.panelDescriptionLabel.text")); // NOI18N
jSplitPane1.setDividerLocation(400);
jSplitPane1.setDividerSize(1);
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);
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
newTagNameButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newTagNameButtonActionPerformed(evt);
}
});
deleteTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete-tag.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(deleteTagNameButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.deleteTagNameButton.text")); // NOI18N
deleteTagNameButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteTagNameButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout modifyTagTypesListPanelLayout = new javax.swing.GroupLayout(modifyTagTypesListPanel);
modifyTagTypesListPanel.setLayout(modifyTagTypesListPanelLayout);
modifyTagTypesListPanelLayout.setHorizontalGroup(
modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(tagTypesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
.addComponent(newTagNameButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deleteTagNameButton)
.addGap(0, 113, Short.MAX_VALUE))
.addComponent(jScrollPane1))
.addContainerGap())
);
modifyTagTypesListPanelLayout.setVerticalGroup(
modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(tagTypesListLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 383, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(newTagNameButton)
.addComponent(deleteTagNameButton))
.addContainerGap())
);
jSplitPane1.setLeftComponent(modifyTagTypesListPanel);
javax.swing.GroupLayout tagTypesAdditionalPanelLayout = new javax.swing.GroupLayout(tagTypesAdditionalPanel);
tagTypesAdditionalPanel.setLayout(tagTypesAdditionalPanelLayout);
tagTypesAdditionalPanelLayout.setHorizontalGroup(
tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 356, Short.MAX_VALUE)
);
tagTypesAdditionalPanelLayout.setVerticalGroup(
tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 456, Short.MAX_VALUE)
);
jSplitPane1.setRightComponent(tagTypesAdditionalPanel);
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(jSplitPane1)
.addComponent(panelDescriptionLabel, 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()
.addContainerGap()
.addComponent(panelDescriptionLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSplitPane1)
.addContainerGap())
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 778, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagNameButtonActionPerformed
NewTagNameDialog dialog = new NewTagNameDialog();
NewTagNameDialog.BUTTON_PRESSED result = dialog.getResult();
if (result == NewTagNameDialog.BUTTON_PRESSED.OK) {
String newTagDisplayName = dialog.getTagName();
TagNameDefiniton newTagType = new TagNameDefiniton(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR);
/*
* If tag name already exists, don't add the tag name.
*/
if (!tagTypes.contains(newTagType)) {
tagTypes.add(newTagType);
updateTagNamesListModel();
tagNamesList.setSelectedValue(newTagType, true);
enableButtons();
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"),
JOptionPane.INFORMATION_MESSAGE);
}
}
}//GEN-LAST:event_newTagNameButtonActionPerformed
private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed
TagNameDefiniton tagName = tagNamesList.getSelectedValue();
tagTypes.remove(tagName);
updateTagNamesListModel();
enableButtons();
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_deleteTagNameButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton deleteTagNameButton;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JPanel modifyTagTypesListPanel;
private javax.swing.JButton newTagNameButton;
private javax.swing.JLabel panelDescriptionLabel;
private javax.swing.JList<org.sleuthkit.autopsy.casemodule.services.TagNameDefiniton> tagNamesList;
private javax.swing.JPanel tagTypesAdditionalPanel;
private javax.swing.JLabel tagTypesListLabel;
// End of variables declaration//GEN-END:variables
/**
* Updates the tag names model for the tag names list component.
*/
private void updateTagNamesListModel() {
tagTypesListModel.clear();
for (TagNameDefiniton tagName : tagTypes) {
tagTypesListModel.addElement(tagName);
}
}
/**
* Loads the stored custom tag types.
*/
@Override
public void load() {
tagTypes = new TreeSet<>(TagNameDefiniton.getTagNameDefinitions());
updateTagNamesListModel();
enableButtons();
}
/**
* Stores the custom tag types.
*/
@Override
public void store() {
TagNameDefiniton.setTagNameDefinitions(tagTypes);
}
/**
* Enables the button components based on the state of the tag types list
* component.
*/
private void enableButtons() {
/*
* Only enable the delete button when there is a tag type selected in
* the tag types JList.
*/
deleteTagNameButton.setEnabled(tagNamesList.getSelectedIndex() != -1);
}
}

View File

@ -22,12 +22,14 @@ import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
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.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.Content;
@ -37,23 +39,20 @@ import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A per case Autopsy service that manages the creation, updating, and deletion
* of tags applied to content and blackboard artifacts by users.
* A per case Autopsy service that manages the addition of content and artifact
* tags to the case database.
*/
public class TagsManager implements Closeable {
private static final Logger logger = Logger.getLogger(TagsManager.class.getName());
private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS
private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS
private SleuthkitCase caseDb;
private final HashMap<String, TagName> uniqueTagNames = new HashMap<>();
private boolean tagNamesLoaded = false;
private static final Logger LOGGER = Logger.getLogger(TagsManager.class.getName());
@NbBundle.Messages("TagsManager.predefTagNames.bookmark.text=Bookmark")
private static final Set<String> STANDARD_TAG_DISPLAY_NAMES = new HashSet<>(Arrays.asList(Bundle.TagsManager_predefTagNames_bookmark_text()));
private final SleuthkitCase caseDb;
/**
* Constructs a per case Autopsy service that manages the creation,
* updating, and deletion of tags applied to content and blackboard
* artifacts by users.
*
* Constructs a per case Autopsy service that manages the addition of
* content and artifact tags to the case database.
*
* @param caseDb The case database.
*/
TagsManager(SleuthkitCase caseDb) {
@ -61,145 +60,152 @@ public class TagsManager implements Closeable {
}
/**
* Gets a list of all tag names currently available for tagging content or
* artifacts.
* Gets a list of all tag names currently in the case database.
*
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
* @return A list, possibly empty, of TagName objects.
*
* @throws TskCoreException If there is an error reading from the case
* database.
* @throws TskCoreException If there is an error querying the case database.
*/
public synchronized List<TagName> getAllTagNames() throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
public List<TagName> getAllTagNames() throws TskCoreException {
return caseDb.getAllTagNames();
}
/**
* Gets a list of all tag names currently in use for tagging content or
* artifacts.
* Gets a list of all tag names currently in use in the case database for
* tagging content or artifacts.
*
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
* @return A list, possibly empty, of TagName objects.
*
* @throws TskCoreException If there is an error reading from the case
* database.
* @throws TskCoreException If there is an error querying the case database.
*/
public synchronized List<TagName> getTagNamesInUse() throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
public List<TagName> getTagNamesInUse() throws TskCoreException {
return caseDb.getTagNamesInUse();
}
/**
* Checks whether a tag name with a given display name exists.
* Gets a map of tag display names to tag name entries in the case database.
* It has keys for the display names of the standard tag types, the current
* user's custom tag types, and the tags in the case database. The value for
* a given key will be null if the corresponding tag type is defined, but a
* tag name entry has not yet added to the case database. In that case,
* addTagName may be called to add the tag name entry.
*
* @param tagDisplayName The display name to check.
* @return A map of tag display names to possibly null TagName object
* references.
*
* @return True or false.
* @throws TskCoreException if there is an error querying the case database.
*/
public synchronized boolean tagNameExists(String tagDisplayName) {
lazyLoadExistingTagNames();
return uniqueTagNames.containsKey(tagDisplayName);
public synchronized Map<String, TagName> getDisplayNamesToTagNamesMap() throws TskCoreException {
/**
* Order is important here. The keys (display names) for the standard
* tag types and current user's custom tag types are added to the map
* first, with null TagName values. If tag name entries exist for those
* keys, loading of the tag names from the database supplies the missing
* values.
*
* Note that creating the map on demand increases the probability that
* the display names of newly added custom tag types and the display
* names of tags added to a multi-user case by other users appear in the
* map.
*/
Map<String, TagName> tagNames = new HashMap<>();
tagNames.put(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), null);
Set<TagNameDefiniton> customTypes = TagNameDefiniton.getTagNameDefinitions();
for (TagNameDefiniton tagType : customTypes) {
tagNames.put(tagType.getDisplayName(), null);
}
for (TagName tagName : caseDb.getAllTagNames()) {
tagNames.put(tagName.getDisplayName(), tagName);
}
return new HashMap<>(tagNames);
}
/**
* Adds a new tag name to the current case and to the tags settings.
* Adds a tag name entry to the case database and adds a corresponding tag
* type to the current user's custom tag types.
*
* @param displayName The display name for the new tag name.
* @param displayName The display name for the new tag type.
*
* @return A TagName data transfer object (DTO) representing the new tag
* name.
* @return A TagName representing the tag name database entry that can be
* used to add instances of the tag type to the case database.
*
* @throws TagNameAlreadyExistsException If the tag name would be a
* duplicate.
* @throws TagNameAlreadyExistsException If the tag name already exists in
* the case database.
* @throws TskCoreException If there is an error adding the tag
* to the case database.
* name to the case database.
*/
public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
public synchronized TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException {
return addTagName(displayName, "", TagName.HTML_COLOR.NONE);
}
/**
* Adds a new tag name to the current case and to the tags settings.
* Adds a tag name entry to the case database and adds a corresponding tag
* type to the current user's custom tag types.
*
* @param displayName The display name for the new tag name.
* @param description The description for the new tag name.
* @param displayName The display name for the new tag type.
* @param description The description for the new tag type.
*
* @return A TagName data transfer object (DTO) representing the new tag
* name.
* @return A TagName object that can be used to add instances of the tag
* type to the case database.
*
* @throws TagNameAlreadyExistsException If the tag name would be a
* duplicate.
* @throws TagNameAlreadyExistsException If the tag name already exists in
* the case database.
* @throws TskCoreException If there is an error adding the tag
* to the case database.
* name to the case database.
*/
public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
public synchronized TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException {
return addTagName(displayName, description, TagName.HTML_COLOR.NONE);
}
/**
* Adds a new tag name to the current case and to the tags settings.
* Adds a tag name entry to the case database and adds a corresponding tag
* type to the current user's custom tag types.
*
* @param displayName The display name for the new tag name.
* @param description The description for the new tag name.
* @param color The HTML color to associate with the new tag name.
* @param displayName The display name for the new tag type.
* @param description The description for the new tag type.
* @param color The color to associate with the new tag type.
*
* @return A TagName data transfer object (DTO) representing the new tag
* name.
* @return A TagName object that can be used to add instances of the tag
* type to the case database.
*
* @throws TagNameAlreadyExistsException If the tag name would be a
* duplicate.
* @throws TagNameAlreadyExistsException If the tag name already exists.
* @throws TskCoreException If there is an error adding the tag
* to the case database.
* name to the case database.
*/
public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
try {
TagName tagName = caseDb.addTagName(displayName, description, color);
if (!STANDARD_TAG_DISPLAY_NAMES.contains(displayName)) {
Set<TagNameDefiniton> customTypes = TagNameDefiniton.getTagNameDefinitions();
customTypes.add(new TagNameDefiniton(displayName, description, color));
TagNameDefiniton.setTagNameDefinitions(customTypes);
}
return tagName;
} catch (TskCoreException ex) {
List<TagName> existingTagNames = caseDb.getAllTagNames();
for (TagName tagName : existingTagNames) {
if (tagName.getDisplayName().equals(displayName)) {
throw new TagNameAlreadyExistsException();
}
}
throw ex;
}
lazyLoadExistingTagNames();
if (uniqueTagNames.containsKey(displayName)) {
throw new TagNameAlreadyExistsException();
}
/*
* Add the tag name to the case.
*/
TagName newTagName = caseDb.addTagName(displayName, description, color);
/*
* Add the tag name to the tags settings.
*/
uniqueTagNames.put(newTagName.getDisplayName(), newTagName);
saveTagNamesToTagsSettings();
return newTagName;
}
/**
* Tags a content object.
*
* @param content The content to tag.
* @param tagName The name to use for the tag.
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
*
* @return A ContentTag data transfer object (DTO) representing the new tag.
* @return A ContentTag object representing the new tag.
*
* @throws TskCoreException If there is an error adding the tag to the case
* database.
*/
public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
return addContentTag(content, tagName, "", -1, -1);
}
@ -207,18 +213,17 @@ public class TagsManager implements Closeable {
* Tags a content object.
*
* @param content The content to tag.
* @param tagName The name to use for the tag.
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
* @param comment A comment to store with the tag.
*
* @return A ContentTag data transfer object (DTO) representing the new tag.
* @return A ContentTag object representing the new tag.
*
* @throws TskCoreException If there is an error adding the tag to the case
* database.
*/
public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
return addContentTag(content, tagName, comment, -1, -1);
}
@ -226,56 +231,25 @@ public class TagsManager implements Closeable {
* Tags a content object or a section of a content object.
*
* @param content The content to tag.
* @param tagName The name to use for the tag.
* @param tagName The representation of the desired tag type in the
* case database, which can be obtained by calling
* getTagNames and/or addTagName.
* @param comment A comment to store with the tag.
* @param beginByteOffset Designates the beginning of a tagged section.
* @param endByteOffset Designates the end of a tagged section.
*
* @return A ContentTag data transfer object (DTO) representing the new tag.
* @return A ContentTag object representing the new tag.
*
* @throws IllegalArgumentException If a requested byte offset is out of
* range.
* @throws TskCoreException If there is an error adding the tag to
* the case database.
* @throws TskCoreException If there is an error adding the tag to the case
* database.
*/
public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
public ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws TskCoreException {
ContentTag tag;
synchronized (this) {
lazyLoadExistingTagNames();
if (null == comment) {
throw new IllegalArgumentException("Passed null comment argument");
}
if (beginByteOffset >= 0 && endByteOffset >= 1) {
if (beginByteOffset > content.getSize() - 1) {
throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(),
"TagsManager.addContentTag.exception.beginByteOffsetOOR.msg",
beginByteOffset, content.getSize() - 1));
}
if (endByteOffset > content.getSize() - 1) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endByteOffsetOOR.msg",
endByteOffset, content.getSize() - 1));
}
if (endByteOffset < beginByteOffset) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg"));
}
}
tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
}
tag = caseDb.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
try {
Case.getCurrentCase().notifyContentTagAdded(tag);
} catch (IllegalStateException ex) {
logger.log(Level.SEVERE, NbBundle.getMessage(TagsManager.class, "TagsManager.addContentTag.noCaseWarning"), ex);
LOGGER.log(Level.SEVERE, "Added a tag to a closed case", ex);
}
return tag;
}
@ -289,18 +263,11 @@ public class TagsManager implements Closeable {
* case database.
*/
public void deleteContentTag(ContentTag tag) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
synchronized (this) {
lazyLoadExistingTagNames();
caseDb.deleteContentTag(tag);
}
caseDb.deleteContentTag(tag);
try {
Case.getCurrentCase().notifyContentTagDeleted(tag);
} catch (IllegalStateException ex) {
logger.log(Level.SEVERE, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteContentTag.noCaseWarning"), ex);
LOGGER.log(Level.SEVERE, "Deleted a tag from a closed case", ex);
}
}
@ -313,17 +280,15 @@ public class TagsManager implements Closeable {
* case database.
*/
public synchronized List<ContentTag> getAllContentTags() throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getAllContentTags();
}
/**
* Gets content tags count by tag name.
*
* @param tagName The tag name of interest.
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
*
* @return A count of the content tags with the specified tag name.
*
@ -331,29 +296,21 @@ public class TagsManager implements Closeable {
* the case database.
*/
public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getContentTagsCountByTagName(tagName);
}
/**
* Gets a content tag by tag id.
*
* @param tagID The tag id of interest.
* @param tagId The tag id of interest.
*
* @return The content tag with the specified tag id.
*
* @throws TskCoreException If there is an error getting the tag from the
* case database.
*/
public synchronized ContentTag getContentTagByTagID(long tagID) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getContentTagByID(tagID);
public synchronized ContentTag getContentTagByTagID(long tagId) throws TskCoreException {
return caseDb.getContentTagByID(tagId);
}
/**
@ -368,10 +325,6 @@ public class TagsManager implements Closeable {
* case database.
*/
public synchronized List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getContentTagsByTagName(tagName);
}
@ -381,172 +334,136 @@ public class TagsManager implements Closeable {
* @param content The content of interest.
*
* @return A list, possibly empty, of the tags that have been applied to the
* artifact.
* content.
*
* @throws TskCoreException If there is an error getting the tags from the
* case database.
*/
public synchronized List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getContentTagsByContent(content);
}
/**
* Tags a blackboard artifact object.
* Tags an artifact.
*
* @param artifact The blackboard artifact to tag.
* @param tagName The name to use for the tag.
* @param artifact The artifact to tag.
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
*
* @return A BlackboardArtifactTag data transfer object (DTO) representing
* the new tag.
* @return A BlackboardArtifactTag object representing the new tag.
*
* @throws TskCoreException If there is an error adding the tag to the case
* database.
*/
public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException {
return addBlackboardArtifactTag(artifact, tagName, "");
}
/**
* Tags a blackboard artifact object.
* Tags an artifact.
*
* @param artifact The blackboard artifact to tag.
* @param tagName The name to use for the tag.
* @param artifact The artifact to tag.
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
* @param comment A comment to store with the tag.
*
* @return A BlackboardArtifactTag data transfer object (DTO) representing
* the new tag.
* @return A BlackboardArtifactTag object representing the new tag.
*
* @throws TskCoreException If there is an error adding the tag to the case
* database.
*/
public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
BlackboardArtifactTag tag;
synchronized (this) {
lazyLoadExistingTagNames();
if (null == comment) {
throw new IllegalArgumentException("Passed null comment argument");
}
tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment);
}
public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
BlackboardArtifactTag tag = caseDb.addBlackboardArtifactTag(artifact, tagName, comment);
try {
Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(tag);
} catch (IllegalStateException ex) {
logger.log(Level.SEVERE, NbBundle.getMessage(TagsManager.class, "TagsManager.addBlackboardArtifactTag.noCaseWarning"), ex);
LOGGER.log(Level.SEVERE, "Added a tag to a closed case", ex);
}
return tag;
}
/**
* Deletes a blackboard artifact tag.
* Deletes an artifact tag.
*
* @param tag The tag to delete.
*
* @throws TskCoreException If there is an error deleting the tag from the
* case database.
*/
public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
synchronized (this) {
lazyLoadExistingTagNames();
caseDb.deleteBlackboardArtifactTag(tag);
}
public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
caseDb.deleteBlackboardArtifactTag(tag);
try {
Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag);
} catch (IllegalStateException ex) {
logger.log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteBlackboardArtifactTag.noCaseWarning"), ex);
LOGGER.log(Level.SEVERE, "Deleted a tag from a closed case", ex);
}
}
/**
* Gets all blackboard artifact tags for the current case.
* Gets all artifact tags for the current case.
*
* @return A list, possibly empty, of blackboard artifact tags.
* @return A list, possibly empty, of artifact tags.
*
* @throws TskCoreException If there is an error getting the tags from the
* case database.
*/
public synchronized List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getAllBlackboardArtifactTags();
}
/**
* Gets blackboard artifact tags count by tag name.
* Gets an artifact tags count by tag name.
*
* @param tagName The tag name of interest.
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
*
* @return A count of the blackboard artifact tags with the specified tag
* name.
* @return A count of the artifact tags with the specified tag name.
*
* @throws TskCoreException If there is an error getting the tags count from
* the case database.
*/
public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getBlackboardArtifactTagsCountByTagName(tagName);
}
/**
* Gets a blackboard artifact tag by tag id.
* Gets an artifact tag by tag id.
*
* @param tagID The tag id of interest.
* @param tagId The tag id of interest.
*
* @return the blackboard artifact tag with the specified tag id.
* @return The artifact tag with the specified tag id.
*
* @throws TskCoreException If there is an error getting the tag from the
* case database.
*/
public synchronized BlackboardArtifactTag getBlackboardArtifactTagByTagID(long tagID) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getBlackboardArtifactTagByID(tagID);
public synchronized BlackboardArtifactTag getBlackboardArtifactTagByTagID(long tagId) throws TskCoreException {
return caseDb.getBlackboardArtifactTagByID(tagId);
}
/**
* Gets blackboard artifact tags by tag name.
* Gets artifact tags by tag name.
*
* @param tagName The tag name of interest.
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
*
* @return A list, possibly empty, of the blackboard artifact tags with the
* specified tag name.
* @return A list, possibly empty, of the artifact tags with the specified
* tag name.
*
* @throws TskCoreException If there is an error getting the tags from the
* case database.
*/
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getBlackboardArtifactTagsByTagName(tagName);
}
/**
* Gets blackboard artifact tags for a particular blackboard artifact.
* Gets artifact tags for a particular artifact.
*
* @param artifact The blackboard artifact of interest.
* @param artifact The artifact of interest.
*
* @return A list, possibly empty, of the tags that have been applied to the
* artifact.
@ -555,115 +472,29 @@ public class TagsManager implements Closeable {
* case database.
*/
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
if (null == caseDb) {
throw new TskCoreException("Tags manager has been closed");
}
lazyLoadExistingTagNames();
return caseDb.getBlackboardArtifactTagsByArtifact(artifact);
}
/**
* Closes the tags manager, saving the avaialble tag names to secondary
* storage.
* Returns true if the tag display name contains an illegal character. Used
* after a tag display name is retrieved from user input.
*
* @throws IOException If there is a problem closing the tags manager.
* @deprecated Tags manager clients should not close the tags manager.
* @param content Display name of the tag being added.
*
* @return boolean indicating whether the name has an invalid character.
*/
@Override
@Deprecated
public synchronized void close() throws IOException {
saveTagNamesToTagsSettings();
caseDb = null;
}
public static boolean containsIllegalCharacters(String content) {
return (content.contains("\\")
|| content.contains(":")
|| content.contains("*")
|| content.contains("?")
|| content.contains("\"")
|| content.contains("<")
|| content.contains(">")
|| content.contains("|")
|| content.contains(",")
|| content.contains(";"));
/**
* Populates the tag names collection and the tag names table in the case
* database with the existing tag names from all sources.
*/
private void lazyLoadExistingTagNames() {
if (!tagNamesLoaded) {
addTagNamesFromCurrentCase();
addTagNamesFromTagsSettings();
addPredefinedTagNames();
saveTagNamesToTagsSettings();
tagNamesLoaded = true;
}
}
/**
* Adds any tag names that are in the case database to the tag names
* collection.
*/
private void addTagNamesFromCurrentCase() {
try {
List<TagName> currentTagNames = caseDb.getAllTagNames();
for (TagName tagName : currentTagNames) {
uniqueTagNames.put(tagName.getDisplayName(), tagName);
}
} catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); //NON-NLS
}
}
/**
* Adds any tag names that are in the properties file to the tag names
* collection and to the case database. The properties file is used to make
* it possible to use tag names across cases.
*/
private void addTagNamesFromTagsSettings() {
String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY);
if (null != setting && !setting.isEmpty()) {
// Read the tag name setting and break it into tag name tuples.
List<String> tagNameTuples = Arrays.asList(setting.split(";"));
// Parse each tuple and add the tag names to the current case, one
// at a time to gracefully discard any duplicates or corrupt tuples.
for (String tagNameTuple : tagNameTuples) {
String[] tagNameAttributes = tagNameTuple.split(",");
if (!uniqueTagNames.containsKey(tagNameAttributes[0])) {
try {
TagName tagName = caseDb.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2]));
uniqueTagNames.put(tagName.getDisplayName(), tagName);
} catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex); //NON-NLS
}
}
}
}
}
/**
* Adds the standard tag names to the tag names collection.
*/
private void addPredefinedTagNames() {
if (!uniqueTagNames.containsKey(NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"))) {
try {
TagName tagName = caseDb.addTagName(
NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), "", TagName.HTML_COLOR.NONE);
uniqueTagNames.put(tagName.getDisplayName(), tagName);
} catch (TskCoreException ex) {
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add standard 'Bookmark' tag name to case database", ex); //NON-NLS
}
}
}
/**
* Saves the tag names to a properties file. The properties file is used to
* make it possible to use tag names across cases.
*/
private void saveTagNamesToTagsSettings() {
if (!uniqueTagNames.isEmpty()) {
StringBuilder setting = new StringBuilder();
for (TagName tagName : uniqueTagNames.values()) {
if (setting.length() != 0) {
setting.append(";");
}
setting.append(tagName.getDisplayName()).append(",");
setting.append(tagName.getDescription()).append(",");
setting.append(tagName.getColor().name());
}
ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString());
}
}
/**
@ -674,4 +505,36 @@ public class TagsManager implements Closeable {
private static final long serialVersionUID = 1L;
}
/**
* Checks whether a tag name with a given display name exists in the case
* database.
*
* @param tagDisplayName The display name.
*
* @return True or false.
*
* @deprecated Not reliable for multi-user cases.
*/
@Deprecated
public synchronized boolean tagNameExists(String tagDisplayName) {
try {
Map<String, TagName> tagNames = getDisplayNamesToTagNamesMap();
return tagNames.containsKey(tagDisplayName) && (tagNames.get(tagDisplayName) != null);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error querying case database for tag names", ex);
return false;
}
}
/**
* Closes the tags manager.
*
* @throws IOException If there is a problem closing the tags manager.
* @deprecated Tags manager clients should not close the tags manager.
*/
@Override
@Deprecated
public synchronized void close() throws IOException {
}
}

View File

@ -0,0 +1,128 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule.services;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javax.swing.JComponent;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
@OptionsPanelController.TopLevelRegistration(
categoryName = "#OptionsCategory_Name_TagNamesOptions",
iconBase = "org/sleuthkit/autopsy/casemodule/services/tag-options-panel-icon.png",
keywords = "#OptionsCategory_TagNames",
keywordsCategory = "CustomTagNames",
position = 8
)
public final class TagsOptionsPanelController extends OptionsPanelController {
private TagOptionsPanel panel;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private boolean changed;
/**
* Component should load its data here.
*/
@Override
public void update() {
getPanel().load();
changed = false;
}
/**
* This method is called when both the Ok and Apply buttons are pressed. It
* applies to any of the panels that have been opened in the process of
* using the options pane.
*/
@Override
public void applyChanges() {
if (changed) {
getPanel().store();
changed = false;
}
}
/**
* This method is called when the Cancel button is pressed. It applies to
* any of the panels that have been opened in the process of using the
* options pane.
*/
@Override
public void cancel() {
}
@Override
public boolean isValid() {
return true;
}
/**
* Used to determine whether any changes have been made to this controller's
* panel.
*
* @return Whether or not a change has been made.
*/
@Override
public boolean isChanged() {
return changed;
}
@Override
public JComponent getComponent(Lookup lkp) {
return getPanel();
}
@Override
public HelpCtx getHelpCtx() {
return null;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
pcs.addPropertyChangeListener(l);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
pcs.removePropertyChangeListener(l);
}
private TagOptionsPanel getPanel() {
if (panel == null) {
panel = new TagOptionsPanel();
panel.addPropertyChangeListener((PropertyChangeEvent evt) -> {
if (evt.getPropertyName().equals(OptionsPanelController.PROP_CHANGED)) {
changed();
}
});
}
return panel;
}
void changed() {
if (!changed) {
changed = true;
pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true);
}
pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -61,6 +61,7 @@ import org.sleuthkit.datamodel.TskCoreException;
//@ServiceProvider(service = DataResultViewer.class)
final class DataResultViewerThumbnail extends AbstractDataResultViewer {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(DataResultViewerThumbnail.class.getName());
//flag to keep track if images are being loaded
private int curPage;
@ -95,7 +96,7 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
iconView.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
em.addPropertyChangeListener(new ExplorerManagerNodeSelectionListener());
thumbnailSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel<String>(
thumbnailSizeComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(
new String[] { Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_small(),
Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_medium(),
Bundle.DataResultViewerThumbnail_thumbnailSizeComboBox_large() }));
@ -395,11 +396,8 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
private void switchPage() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
EventQueue.invokeLater(() -> {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
});
//Note the nodes factories are likely creating nodes in EDT anyway, but worker still helps
@ -437,7 +435,7 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
ex.getMessage()),
NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(d);
logger.log(Level.SEVERE, "Error making thumbnails: " + ex.getMessage()); //NON-NLS
logger.log(Level.SEVERE, "Error making thumbnails: {0}", ex.getMessage()); //NON-NLS
} // catch and ignore if we were cancelled
catch (java.util.concurrent.CancellationException ex) {
}
@ -453,6 +451,7 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
goToPageField.setEnabled(false);
pageNumLabel.setText("");
imagesRangeLabel.setText("");
thumbnailSizeComboBox.setEnabled(false);
} else {
pageNumLabel.setText(
NbBundle.getMessage(this.getClass(), "DataResultViewerThumbnail.pageNumbers.curOfTotal",
@ -464,7 +463,7 @@ final class DataResultViewerThumbnail extends AbstractDataResultViewer {
pageNextButton.setEnabled(!(curPage == totalPages));
pagePrevButton.setEnabled(!(curPage == 1));
goToPageField.setEnabled(totalPages > 1);
thumbnailSizeComboBox.setEnabled(true);
}
}

View File

@ -22,6 +22,12 @@ import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children.Keys;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters;
import org.sleuthkit.autopsy.datamodel._private.RecentFiles;
import org.sleuthkit.autopsy.datamodel._private.Accounts;
import org.sleuthkit.autopsy.datamodel._private.Accounts.AccountsRootNode;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory;

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,6 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskException;
@ -68,7 +67,7 @@ public class ArtifactStringContent implements StringContent {
buffer.append("<tr>"); //NON-NLS
buffer.append("</tr>\n"); //NON-NLS
// cycle through each attribute and display in a row in the table.
// cycle through each attribute and display in a row in the table.
for (BlackboardAttribute attr : artifact.getAttributes()) {
// name column
@ -78,48 +77,36 @@ public class ArtifactStringContent implements StringContent {
// value column
buffer.append("<td>"); //NON-NLS
if (attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID()
|| attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID()
|| attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID()
|| attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED.getTypeID()
|| attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID()
|| attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()
|| attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID()
|| attr.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()) {
long epoch = attr.getValueLong();
String time = "0000-00-00 00:00:00";
if (epoch != 0) {
dateFormatter.setTimeZone(getTimeZone(artifact));
time = dateFormatter.format(new java.util.Date(epoch * 1000));
}
buffer.append(time);
} else {
switch (attr.getAttributeType().getValueType()) {
case STRING:
String str = attr.getValueString();
str = str.replaceAll(" ", "&nbsp;"); //NON-NLS
str = str.replaceAll("<", "&lt;"); //NON-NLS
str = str.replaceAll(">", "&gt;"); //NON-NLS
str = str.replaceAll("(\r\n|\n)", "<br />"); //NON-NLS
buffer.append(str);
break;
case INTEGER:
buffer.append(attr.getValueInt());
break;
case LONG:
buffer.append(attr.getValueLong());
break;
case DOUBLE:
buffer.append(attr.getValueDouble());
break;
case BYTE:
buffer.append(Arrays.toString(attr.getValueBytes()));
break;
case DATETIME:
buffer.append(attr.getValueLong());
break;
}
switch (attr.getAttributeType().getValueType()) {
case STRING:
String str = attr.getValueString();
str = str.replaceAll(" ", "&nbsp;"); //NON-NLS
str = str.replaceAll("<", "&lt;"); //NON-NLS
str = str.replaceAll(">", "&gt;"); //NON-NLS
str = str.replaceAll("(\r\n|\n)", "<br />"); //NON-NLS
buffer.append(str);
break;
case INTEGER:
buffer.append(attr.getValueInt());
break;
case LONG:
buffer.append(attr.getValueLong());
break;
case DOUBLE:
buffer.append(attr.getValueDouble());
break;
case BYTE:
buffer.append(Arrays.toString(attr.getValueBytes()));
break;
case DATETIME:
long epoch = attr.getValueLong();
String time = "0000-00-00 00:00:00";
if (epoch != 0) {
dateFormatter.setTimeZone(getTimeZone(artifact));
time = dateFormatter.format(new java.util.Date(epoch * 1000));
}
buffer.append(time);
break;
}
if (!"".equals(attr.getContext())) {
buffer.append(" (");

View File

@ -185,13 +185,13 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
ss = Sheet.createPropertiesSet();
s.put(ss);
}
final String NO_DESCR = NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.noDesc.text");
final String NO_DESCR = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.noDesc.text");
Map<String, Object> map = new LinkedHashMap<>();
fillPropertyMap(map, artifact);
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.srcFile.name"),
NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.srcFile.displayName"),
ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.displayName"),
NO_DESCR,
this.getDisplayName()));
@ -222,13 +222,13 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
actualMimeType = ""; //NON-NLS
}
}
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.ext.name"),
NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.ext.displayName"),
ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.displayName"),
NO_DESCR,
ext));
ss.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.name"),
NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.displayName"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.displayName"),
NO_DESCR,
actualMimeType));
}
@ -243,32 +243,32 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
if (sourcePath.isEmpty() == false) {
ss.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.filePath.name"),
NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.filePath.displayName"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.displayName"),
NO_DESCR,
sourcePath));
}
if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
AbstractFile file = associated instanceof AbstractFile ? (AbstractFile) associated : null;
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"),
ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getMtime(), file) : ""));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"),
ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getCtime(), file) : ""));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"),
ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getAtime(), file) : ""));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"),
ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"),
"",
file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : ""));
ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"),
ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"),
"",
associated.getSize()));
}
@ -287,8 +287,8 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
if (dataSourceStr.isEmpty() == false) {
ss.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.dataSrc.name"),
NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.dataSrc.displayName"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.displayName"),
NO_DESCR,
dataSourceStr));
}

View File

@ -118,17 +118,6 @@ FileSize.createSheet.filterType.displayName=Filter Type
FileSize.createSheet.filterType.desc=no description
FileSize.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0}
FileTypeChildren.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0}
FileTypeExtensionFilters.tskImgFilter.text=Images
FileTypeExtensionFilters.tskVideoFilter.text=Videos
FileTypeExtensionFilters.tskAudioFilter.text=Audio
FileTypeExtensionFilters.tskArchiveFilter.text=Archives
FileTypeExtensionFilters.tskDocumentFilter.text=Documents
FileTypeExtensionFilters.tskExecFilter.text=Executable
FileTypeExtensionFilters.autDocHtmlFilter.text=HTML
FileTypeExtensionFilters.autDocOfficeFilter.text=Office
FileTypeExtensionFilters.autoDocPdfFilter.text=PDF
FileTypeExtensionFilters.autDocTxtFilter.text=Plain Text
FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text
FileTypeNode.createSheet.filterType.name=Filter Type
FileTypeNode.createSheet.filterType.displayName=Filter Type
FileTypeNode.createSheet.filterType.desc=no description

View File

@ -0,0 +1,171 @@
package org.sleuthkit.autopsy.datamodel;
import com.google.common.collect.Range;
import com.google.common.collect.RangeMap;
import com.google.common.collect.TreeRangeMap;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel._private.BINRange;
public class CreditCards {
//Interface for objects that provide details about one or more BINs.
static public interface BankIdentificationNumber {
/**
* Get the city of the issuer.
*
* @return the city of the issuer.
*/
Optional<String> getBankCity();
/**
* Get the name of the issuer.
*
* @return the name of the issuer.
*/
Optional<String> getBankName();
/**
* Get the phone number of the issuer.
*
* @return the phone number of the issuer.
*/
Optional<String> getBankPhoneNumber();
/**
* Get the URL of the issuer.
*
* @return the URL of the issuer.
*/
Optional<String> getBankURL();
/**
* Get the brand of this BIN range.
*
* @return the brand of this BIN range.
*/
Optional<String> getBrand();
/**
* Get the type of card (credit vs debit) for this BIN range.
*
* @return the type of cards in this BIN range.
*/
Optional<String> getCardType();
/**
* Get the country of the issuer.
*
* @return the country of the issuer.
*/
Optional<String> getCountry();
/**
* Get the length of account numbers in this BIN range.
*
* NOTE: the length is currently unused, and not in the data file for
* any ranges. It could be quite helpfull for validation...
*
* @return the length of account numbers in this BIN range. Or an empty
* Optional if the length is unknown.
*
*/
Optional<Integer> getNumberLength();
/**
* Get the scheme this BIN range uses to amex,visa,mastercard, etc
*
* @return the scheme this BIN range uses.
*/
Optional<String> getScheme();
}
private static final Logger LOGGER = Logger.getLogger(CreditCards.class.getName());
/**
* Range Map from a (ranges of) BINs to data model object with details of
* the BIN, ie, bank name, phone, url, visa/amex/mastercard/...,
*/
@GuardedBy("CreditCards.class")
private final static RangeMap<Integer, BINRange> binRanges = TreeRangeMap.create();
/**
* Flag for if we have loaded the BINs from the file already.
*/
@GuardedBy("CreditCards.class")
private static boolean binsLoaded = false;
/**
* Load the BIN range information from disk. If the map has already been
* initialized, don't load again.
*/
synchronized private static void loadBINRanges() {
if (binsLoaded == false) {
try {
InputStreamReader in = new InputStreamReader(CreditCards.class.getResourceAsStream("ranges.csv")); //NON-NLS
CSVParser rangesParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in);
//parse each row and add to range map
for (CSVRecord record : rangesParser) {
/**
* Because ranges.csv allows both 6 and (the newer) 8 digit
* BINs, but we need a consistent length for the range map,
* we pad all the numbers out to 8 digits
*/
String start = StringUtils.rightPad(record.get("iin_start"), 8, "0"); //pad start with 0's //NON-NLS
//if there is no end listed, use start, since ranges will be closed.
String end = StringUtils.defaultIfBlank(record.get("iin_end"), start); //NON-NLS
end = StringUtils.rightPad(end, 8, "99"); //pad end with 9's //NON-NLS
final String numberLength = record.get("number_length"); //NON-NLS
try {
BINRange binRange = new BINRange(Integer.parseInt(start),
Integer.parseInt(end),
StringUtils.isBlank(numberLength) ? null : Integer.valueOf(numberLength),
record.get("scheme"), //NON-NLS
record.get("brand"), //NON-NLS
record.get("type"), //NON-NLS
record.get("country"), //NON-NLS
record.get("bank_name"), //NON-NLS
record.get("bank_url"), //NON-NLS
record.get("bank_phone"), //NON-NLS
record.get("bank_city")); //NON-NLS
binRanges.put(Range.closed(binRange.getBINstart(), binRange.getBINend()), binRange);
} catch (NumberFormatException numberFormatException) {
LOGGER.log(Level.WARNING, "Failed to parse BIN range: " + record.toString(), numberFormatException); //NON-NLS
}
binsLoaded = true;
}
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "Failed to load BIN ranges form ranges.csv", ex); //NON-NLS
MessageNotifyUtil.Notify.warn("Credit Card Number Discovery", "There was an error loading Bank Identification Number information. Accounts will not have their BINs identified.");
}
}
}
/**
* Get an BINInfo object with details about the given BIN
*
* @param bin the BIN to get details of.
*
* @return
*/
synchronized static public BankIdentificationNumber getBINInfo(int bin) {
loadBINRanges();
return binRanges.get(bin);
}
}

View File

@ -18,6 +18,9 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
/**
* Root node to store the data sources in a case
*/

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;

View File

@ -22,6 +22,7 @@ import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.De
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode;
import org.sleuthkit.autopsy.datamodel._private.Accounts;
/**
* Visitor pattern that goes over all nodes in the directory tree. This includes
@ -127,7 +128,7 @@ public interface DisplayableItemNodeVisitor<T> {
*/
T visit(Accounts.AccountsRootNode accountRootNode);
T visit(Accounts.AccountTypeNode accountTypeNode);
T visit(Accounts.CreditCardNumberAccountTypeNode accountTypeNode);
T visit(Accounts.ByBINNode byArtifactNode);
@ -137,6 +138,8 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(Accounts.BINNode binNode);
T visit(Accounts.DefaultAccountTypeNode node);
/**
* Visitor with an implementable default behavior for all types. Override
* specific visit types to not use the default behavior.
@ -350,7 +353,7 @@ public interface DisplayableItemNodeVisitor<T> {
}
@Override
public T visit(Accounts.AccountTypeNode node) {
public T visit(Accounts.CreditCardNumberAccountTypeNode node) {
return defaultVisit(node);
}
@ -378,5 +381,9 @@ public interface DisplayableItemNodeVisitor<T> {
public T visit(Accounts.BINNode node) {
return defaultVisit(node);
}
@Override
public T visit(Accounts.DefaultAccountTypeNode node) {
return defaultVisit(node);
}
}
}

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
@ -37,7 +39,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT;
@ -201,7 +203,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
doNotShow.add(new BlackboardArtifact.Type(TSK_KEYWORD_HIT));
doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_FILE_HIT));
doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT));
doNotShow.add(new BlackboardArtifact.Type(TSK_CREDIT_CARD_ACCOUNT));
doNotShow.add(new BlackboardArtifact.Type(TSK_ACCOUNT));
}
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.RecentFiles;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;

View File

@ -28,7 +28,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.datamodel.RecentFiles.RecentFilesFilter;
import org.sleuthkit.autopsy.datamodel._private.RecentFiles.RecentFilesFilter;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;

View File

@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.datamodel.RecentFiles.RecentFilesFilter;
import org.sleuthkit.autopsy.datamodel._private.RecentFiles.RecentFilesFilter;
import org.sleuthkit.datamodel.SleuthkitCase;
/**

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import org.sleuthkit.datamodel.SleuthkitCase;
/**

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.Accounts;
import java.util.Arrays;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel._private.AutopsyVisitableItem;
import org.sleuthkit.datamodel.SleuthkitCase;
/**

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.datamodel;
import org.sleuthkit.autopsy.datamodel._private.FileTypeExtensionFilters;
import java.util.Arrays;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;

File diff suppressed because it is too large Load Diff

View File

@ -16,14 +16,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datamodel;
package org.sleuthkit.autopsy.datamodel._private;
import org.sleuthkit.autopsy.datamodel.DataSources;
import org.sleuthkit.autopsy.datamodel.DeletedContent;
import org.sleuthkit.autopsy.datamodel.EmailExtracted;
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
import org.sleuthkit.autopsy.datamodel.FileSize;
import org.sleuthkit.autopsy.datamodel.HashsetHits;
import org.sleuthkit.autopsy.datamodel.InterestingHits;
import org.sleuthkit.autopsy.datamodel.KeywordHits;
import org.sleuthkit.autopsy.datamodel.Reports;
import org.sleuthkit.autopsy.datamodel.Results;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.Views;
/**
* This visitor goes over the AutopsyVisitableItems, which are currently the
* nodes in the tree that are structural and not nodes that are from
* Sleuthkit-based data model objects.
*/
interface AutopsyItemVisitor<T> {
public interface AutopsyItemVisitor<T> {
T visit(DataSources i);

View File

@ -16,13 +16,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datamodel;
package org.sleuthkit.autopsy.datamodel._private;
;
/**
* AutopsyVisitableItems are the nodes in the directory tree that are for
* structure only. They are not associated with content objects.
*/
interface AutopsyVisitableItem {
public interface AutopsyVisitableItem {
/**
* visitor pattern support

View File

@ -0,0 +1,146 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datamodel._private;
import java.util.Optional;
import javax.annotation.concurrent.Immutable;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.datamodel.CreditCards;
/**
* Details of a range of Bank Identification Number(s) (BIN) used by a bank.
*/
@Immutable
public class BINRange implements CreditCards.BankIdentificationNumber {
private final int BINStart; //start of BIN range, 8 digits
private final int BINEnd; // end (incluse ) of BIN rnage, 8 digits
private final Integer numberLength; // the length of accounts numbers with this BIN, currently unused
/**
* AMEX, VISA, MASTERCARD, DINERS, DISCOVER, UNIONPAY
*/
private final String scheme;
private final String brand;
/**
* DEBIT, CREDIT
*/
private final String cardType;
private final String country;
private final String bankName;
private final String bankCity;
private final String bankURL;
private final String bankPhoneNumber;
/**
* Constructor
*
* @param BIN_start the first BIN in the range, must be 8 digits
* @param BIN_end the last(inclusive) BIN in the range, must be 8
* digits
* @param number_length the length of account numbers in this BIN range
* @param scheme amex/visa/mastercard/etc
* @param brand the brand of this BIN range
* @param type credit vs debit
* @param country the country of the issuer
* @param bank_name the name of the issuer
* @param bank_url the url of the issuer
* @param bank_phone the phone number of the issuer
* @param bank_city the city of the issuer
*/
public BINRange(int BIN_start, int BIN_end, Integer number_length, String scheme, String brand, String type, String country, String bank_name, String bank_url, String bank_phone, String bank_city) {
this.BINStart = BIN_start;
this.BINEnd = BIN_end;
this.numberLength = number_length;
this.scheme = StringUtils.defaultIfBlank(scheme, null);
this.brand = StringUtils.defaultIfBlank(brand, null);
this.cardType = StringUtils.defaultIfBlank(type, null);
this.country = StringUtils.defaultIfBlank(country, null);
this.bankName = StringUtils.defaultIfBlank(bank_name, null);
this.bankURL = StringUtils.defaultIfBlank(bank_url, null);
this.bankPhoneNumber = StringUtils.defaultIfBlank(bank_phone, null);
this.bankCity = StringUtils.defaultIfBlank(bank_city, null);
}
/**
* Get the first BIN in this range
*
* @return the first BIN in this range.
*/
public int getBINstart() {
return BINStart;
}
/**
* Get the last (inclusive) BIN in this range.
*
* @return the last (inclusive) BIN in this range.
*/
public int getBINend() {
return BINEnd;
}
@Override
public Optional<Integer> getNumberLength() {
return Optional.ofNullable(numberLength);
}
@Override
public Optional<String> getScheme() {
return Optional.ofNullable(scheme);
}
@Override
public Optional<String> getBrand() {
return Optional.ofNullable(brand);
}
@Override
public Optional<String> getCardType() {
return Optional.ofNullable(cardType);
}
@Override
public Optional<String> getCountry() {
return Optional.ofNullable(country);
}
@Override
public Optional<String> getBankName() {
return Optional.ofNullable(bankName);
}
@Override
public Optional<String> getBankURL() {
return Optional.ofNullable(bankURL);
}
@Override
public Optional<String> getBankPhoneNumber() {
return Optional.ofNullable(bankPhoneNumber);
}
@Override
public Optional<String> getBankCity() {
return Optional.ofNullable(bankCity);
}
}

View File

@ -0,0 +1,12 @@
FileTypeExtensionFilters.tskImgFilter.text=Images
FileTypeExtensionFilters.tskVideoFilter.text=Videos
FileTypeExtensionFilters.tskAudioFilter.text=Audio
FileTypeExtensionFilters.tskArchiveFilter.text=Archives
FileTypeExtensionFilters.tskDocumentFilter.text=Documents
FileTypeExtensionFilters.tskExecFilter.text=Executable
FileTypeExtensionFilters.autDocHtmlFilter.text=HTML
FileTypeExtensionFilters.autDocOfficeFilter.text=Office
FileTypeExtensionFilters.autoDocPdfFilter.text=PDF
FileTypeExtensionFilters.autDocTxtFilter.text=Plain Text
FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text

View File

@ -16,20 +16,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datamodel;
package org.sleuthkit.autopsy.datamodel._private;
import java.util.Arrays;
import java.util.List;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
import org.sleuthkit.datamodel.SleuthkitCase;
/**
* Filters database results by file extension.
*/
class FileTypeExtensionFilters implements AutopsyVisitableItem {
public class FileTypeExtensionFilters implements AutopsyVisitableItem {
private SleuthkitCase skCase;
private final SleuthkitCase skCase;
// root node filters
public enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface {
@ -53,10 +53,10 @@ class FileTypeExtensionFilters implements AutopsyVisitableItem {
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.tskExecFilter.text"),
Arrays.asList(".exe", ".dll", ".bat", ".cmd", ".com")); //NON-NLS
private int id;
private String name;
private String displayName;
private List<String> filter;
private final int id;
private final String name;
private final String displayName;
private final List<String> filter;
private RootFilter(int id, String name, String displayName, List<String> filter) {
this.id = id;
@ -110,10 +110,10 @@ class FileTypeExtensionFilters implements AutopsyVisitableItem {
NbBundle.getMessage(FileTypeExtensionFilters.class, "FileTypeExtensionFilters.autDocRtfFilter.text"),
Arrays.asList(".rtf")); //NON-NLS
private int id;
private String name;
private String displayName;
private List<String> filter;
private final int id;
private final String name;
private final String displayName;
private final List<String> filter;
private DocumentFilter(int id, String name, String displayName, List<String> filter) {
this.id = id;
@ -157,10 +157,10 @@ class FileTypeExtensionFilters implements AutopsyVisitableItem {
ExecutableFilter_CMD(3, "ExecutableFilter_CMD", ".cmd", Arrays.asList(".cmd")), //NON-NLS
ExecutableFilter_COM(4, "ExecutableFilter_COM", ".com", Arrays.asList(".com")); //NON-NLS
private int id;
private String name;
private String displayName;
private List<String> filter;
private final int id;
private final String name;
private final String displayName;
private final List<String> filter;
private ExecutableFilter(int id, String name, String displayName, List<String> filter) {
this.id = id;
@ -208,7 +208,7 @@ class FileTypeExtensionFilters implements AutopsyVisitableItem {
return this.skCase;
}
interface SearchFilterInterface {
public interface SearchFilterInterface {
public String getName();

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datamodel;
package org.sleuthkit.autopsy.datamodel._private;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -25,7 +25,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
* Recent files node support NOTE: As of june '15 we do not display this in the
* tree. It can be added back when we have filtering in the results area.
*/
class RecentFiles implements AutopsyVisitableItem {
public class RecentFiles implements AutopsyVisitableItem {
SleuthkitCase skCase;

View File

@ -37,38 +37,15 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.Accounts;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
import org.sleuthkit.autopsy.datamodel.DirectoryNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.EmailExtracted;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.AccountNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted.FolderNode;
import org.sleuthkit.autopsy.datamodel.ExtractedContent;
import org.sleuthkit.autopsy.datamodel.ExtractedContent.TypeNode;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode;
import org.sleuthkit.autopsy.datamodel.FileTypeNode;
import org.sleuthkit.autopsy.datamodel.FileTypesNode;
import org.sleuthkit.autopsy.datamodel.HashsetHits;
import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetNameNode;
import org.sleuthkit.autopsy.datamodel.ImageNode;
import org.sleuthkit.autopsy.datamodel.InterestingHits;
import org.sleuthkit.autopsy.datamodel.KeywordHits;
import org.sleuthkit.autopsy.datamodel.KeywordHits.ListNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.TermNode;
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
import org.sleuthkit.autopsy.datamodel.Reports;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
import org.sleuthkit.autopsy.datamodel.VolumeNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -301,112 +278,12 @@ public class DataResultFilterNode extends FilterNode {
*/
private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default<AbstractAction> {
@Override
public AbstractAction visit(ImageNode in) {
return openChild(in);
}
@Override
public AbstractAction visit(VolumeNode vn) {
return openChild(vn);
}
@Override
public AbstractAction visit(ExtractedContent.RootNode ecn) {
return openChild(ecn);
}
@Override
public AbstractAction visit(KeywordHits.RootNode khrn) {
return openChild(khrn);
}
@Override
public AbstractAction visit(HashsetHits.RootNode hhrn) {
return openChild(hhrn);
}
@Override
public AbstractAction visit(HashsetNameNode hhsn) {
return openChild(hhsn);
}
@Override
public AbstractAction visit(InterestingHits.RootNode iarn) {
return openChild(iarn);
}
@Override
public AbstractAction visit(InterestingHits.SetNameNode iasn) {
return openChild(iasn);
}
@Override
public AbstractAction visit(EmailExtracted.RootNode eern) {
return openChild(eern);
}
@Override
public AbstractAction visit(AccountNode eean) {
return openChild(eean);
}
@Override
public AbstractAction visit(FolderNode eefn) {
return openChild(eefn);
}
@Override
public AbstractAction visit(RecentFilesNode rfn) {
return openChild(rfn);
}
@Override
public AbstractAction visit(DeletedContentsNode dcn) {
return openChild(dcn);
}
@Override
public AbstractAction visit(DeletedContentNode dcn) {
return openChild(dcn);
}
@Override
public AbstractAction visit(FileSizeRootNode fsrn) {
return openChild(fsrn);
}
@Override
public AbstractAction visit(FileSizeNode fsn) {
return openChild(fsn);
}
@Override
public AbstractAction visit(BlackboardArtifactNode ban) {
return new ViewContextAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInDir.text"), ban);
}
@Override
public AbstractAction visit(TypeNode atn) {
return openChild(atn);
}
@Override
public AbstractAction visit(Tags.TagNameNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(Tags.ContentTagTypeNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(Tags.BlackboardArtifactTagTypeNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(DirectoryNode dn) {
if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) {
@ -418,11 +295,6 @@ public class DataResultFilterNode extends FilterNode {
}
}
@Override
public AbstractAction visit(VirtualDirectoryNode ldn) {
return openChild(ldn);
}
@Override
public AbstractAction visit(FileNode fn) {
if (fn.hasContentChildren()) {
@ -441,69 +313,14 @@ public class DataResultFilterNode extends FilterNode {
}
}
@Override
public AbstractAction visit(FileTypeNode fsfn) {
return openChild(fsfn);
}
@Override
public AbstractAction visit(FileTypesNode sfn) {
return openChild(sfn);
}
@Override
public AbstractAction visit(RecentFilesFilterNode rffn) {
return openChild(rffn);
}
@Override
public AbstractAction visit(ListNode khsn) {
return openChild(khsn);
}
@Override
public AbstractAction visit(TermNode khmln) {
return openChild(khmln);
}
@Override
public AbstractAction visit(Reports.ReportNode reportNode) {
return reportNode.getPreferredAction();
}
@Override
public AbstractAction visit(Accounts.BINNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(Accounts.FileWithCCNNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(Accounts.ByFileNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(Accounts.ByBINNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(Accounts.AccountsRootNode node) {
return openChild(node);
}
@Override
public AbstractAction visit(Accounts.AccountTypeNode node) {
return openChild(node);
}
@Override
protected AbstractAction defaultVisit(DisplayableItemNode c) {
return null;
return openChild(c);
}
/**

View File

@ -57,7 +57,6 @@ import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.Accounts;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.DataSources;
import org.sleuthkit.autopsy.datamodel.DataSourcesNode;
@ -71,6 +70,7 @@ import org.sleuthkit.autopsy.datamodel.RootContentChildren;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.Views;
import org.sleuthkit.autopsy.datamodel.ViewsNode;
import org.sleuthkit.autopsy.datamodel._private.Accounts;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;

View File

@ -40,7 +40,7 @@ public class ExternalViewerAction extends AbstractAction {
private final static Logger logger = Logger.getLogger(ExternalViewerAction.class.getName());
private org.sleuthkit.datamodel.AbstractFile fileObject;
final static String[] EXECUTABLE_EXT = {".exe", ".dll", ".com", ".bat", ".msi", ".reg", ".scr"}; //NON-NLS
final static String[] EXECUTABLE_EXT = {".exe", ".dll", ".com", ".bat", ".msi", ".reg", ".scr", ".cmd"}; //NON-NLS
public ExternalViewerAction(String title, Node fileNode) {
super(title);

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -254,8 +254,8 @@ class ReportHTML implements TableReportModule {
case TSK_REMOTE_DRIVE:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/drive_network.png"); //NON-NLS
break;
case TSK_CREDIT_CARD_ACCOUNT:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/credit-card.png"); //NON-NLS
case TSK_ACCOUNT:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS
break;
default:
logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = " + dataType); //NON-NLS
@ -264,7 +264,17 @@ class ReportHTML implements TableReportModule {
iconFilePath = path + File.separator + iconFileName;
break;
}
} else { // no defined artifact found for this dataType
} else if (dataType.startsWith(ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName())) {
/* TSK_ACCOUNT artifacts get separated by their TSK_ACCOUNT_TYPE
* attribute, with a synthetic compound dataType name, so they are
* not caught by the switch statement above. For now we just give
* them all the general account icon, but we could do something else
* in the future.
*/
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS
iconFileName = "accounts.png"; //NON-NLS
iconFilePath = path + File.separator + iconFileName;
} else { // no defined artifact found for this dataType
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS
iconFileName = "star.png"; //NON-NLS
iconFilePath = path + File.separator + iconFileName;

View File

@ -18,12 +18,16 @@
*/
package org.sleuthkit.autopsy.report;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimaps;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -43,6 +47,7 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.Type;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -119,10 +124,10 @@ class TableReportGenerator {
*/
private void makeBlackboardArtifactTables() {
// Make a comment string describing the tag names filter in effect.
StringBuilder comment = new StringBuilder();
String comment = "";
if (!tagNamesFilter.isEmpty()) {
comment.append(NbBundle.getMessage(this.getClass(), "ReportGenerator.artifactTable.taggedResults.text"));
comment.append(makeCommaSeparatedList(tagNamesFilter));
comment += NbBundle.getMessage(this.getClass(), "ReportGenerator.artifactTable.taggedResults.text");
comment += makeCommaSeparatedList(tagNamesFilter);
}
// Add a table to the report for every enabled blackboard artifact type.
@ -139,10 +144,10 @@ class TableReportGenerator {
// Keyword hits and hashset hit artifacts get special handling.
if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
writeKeywordHits(tableReport, comment.toString(), tagNamesFilter);
writeKeywordHits(tableReport, comment, tagNamesFilter);
continue;
} else if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
writeHashsetHits(tableReport, comment.toString(), tagNamesFilter);
writeHashsetHits(tableReport, comment, tagNamesFilter);
continue;
}
@ -152,54 +157,92 @@ class TableReportGenerator {
continue;
}
/*
Gets all of the attribute types of this artifact type by adding
all of the types to a set
*/
Set<BlackboardAttribute.Type> attrTypeSet = new TreeSet<>((BlackboardAttribute.Type o1, BlackboardAttribute.Type o2) -> o1.getDisplayName().compareTo(o2.getDisplayName()));
for (ArtifactData data : artifactList) {
List<BlackboardAttribute> attributes = data.getAttributes();
for (BlackboardAttribute attribute : attributes) {
attrTypeSet.add(attribute.getAttributeType());
/* TSK_ACCOUNT artifacts get grouped by their TSK_ACCOUNT_TYPE
* attribute, and then handed off to the standard method for writing
* tables. */
if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
//Group account artifacts by their account type
ListMultimap<String, ArtifactData> groupedArtifacts = Multimaps.index(artifactList,
artifactData -> {
try {
return artifactData.getArtifact().getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)).getValueString();
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Unable to get value of TSK_ACCOUNT_TYPE attribute. Defaulting to \"unknown\"", ex);
return "unknown";
}
});
for (String accountType : groupedArtifacts.keySet()) {
/* If the report is a ReportHTML, the data type name
* eventualy makes it to useDataTypeIcon which expects but
* does not require a artifact name, so we make a synthetic
* compund name by appending a ":" and the account type.
*/
final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountType;
writeTableForDataType(groupedArtifacts.get(accountType), type, compundDataTypeName, comment);
}
} else {
//all other artifact types are sent to writeTableForDataType directly
writeTableForDataType(artifactList, type, type.getDisplayName(), comment);
}
// Get the columns appropriate for the artifact type. This is
// used to get the data that will be in the cells below based on
// type, and display the column headers.
List<Column> columns = getArtifactTableColumns(type.getTypeID(), attrTypeSet);
if (columns.isEmpty()) {
continue;
}
columnHeaderMap.put(type.getTypeID(), columns);
// The artifact list is sorted now, as getting the row data is
// dependent on having the columns, which is necessary for
// sorting.
Collections.sort(artifactList);
List<String> columnHeaderNames = new ArrayList<>();
for (Column currColumn : columns) {
columnHeaderNames.add(currColumn.getColumnHeader());
}
tableReport.startDataType(type.getDisplayName(), comment.toString());
tableReport.startTable(columnHeaderNames);
for (ArtifactData artifactData : artifactList) {
// Get the row data for this artifact, and has the
// module add it.
List<String> rowData = artifactData.getRow();
if (rowData.isEmpty()) {
continue;
}
tableReport.addRow(rowData);
}
// Finish up this data type
progressPanel.increment();
tableReport.endTable();
tableReport.endDataType();
}
}
/**
*
* Write the given list of artifacts to the table for the given type.
*
* @param artifactList The List of artifacts to include in the table.
* @param type The Type of artifacts included in the table. All the
* artifacts in artifactList should be of this type.
* @param tableName The name of the table.
* @param comment A comment to put in the header.
*/
private void writeTableForDataType(List<ArtifactData> artifactList, BlackboardArtifact.Type type, String tableName, String comment) {
/*
* Make a sorted set of all of the attribute types that are on any of
* the given artifacts.
*/
Set<BlackboardAttribute.Type> attrTypeSet = new TreeSet<>(Comparator.comparing(BlackboardAttribute.Type::getDisplayName));
for (ArtifactData data : artifactList) {
List<BlackboardAttribute> attributes = data.getAttributes();
for (BlackboardAttribute attribute : attributes) {
attrTypeSet.add(attribute.getAttributeType());
}
}
/* Get the columns appropriate for the artifact type. This is used to
* get the data that will be in the cells below based on type, and
* display the column headers.
*/
List<Column> columns = getArtifactTableColumns(type.getTypeID(), attrTypeSet);
if (columns.isEmpty()) {
return;
}
columnHeaderMap.put(type.getTypeID(), columns);
/* The artifact list is sorted now, as getting the row data is dependent
* on having the columns, which is necessary for sorting.
*/
Collections.sort(artifactList);
tableReport.startDataType(tableName, comment);
tableReport.startTable(Lists.transform(columns, Column::getColumnHeader));
for (ArtifactData artifactData : artifactList) {
// Get the row data for this artifact, and has the
// module add it.
List<String> rowData = artifactData.getRow();
if (rowData.isEmpty()) {
return;
}
tableReport.addRow(rowData);
}
// Finish up this data type
progressPanel.increment();
tableReport.endTable();
tableReport.endDataType();
}
/**
* Make table for tagged files
*/
@ -1449,8 +1492,9 @@ class TableReportGenerator {
columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.remotePath"),
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REMOTE_PATH)));
} else if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID()) {
} else if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
columns.add(new StatusColumn());
attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE));
} else {
// This is the case that it is a custom type. The reason an else is
// necessary is to make sure that the source file column is added
@ -1584,6 +1628,7 @@ class TableReportGenerator {
}
}
private class AttributeColumn implements Column {
private final String columnHeader;
@ -1643,10 +1688,6 @@ class TableReportGenerator {
@Override
public String getCellData(ArtifactData artData) {
return getFileUniquePath(artData.getContent());
/*else if (this.columnHeader.equals(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))) {
return makeCommaSeparatedList(artData.getTags());
}
return "";*/
}
@Override

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
@ -127,7 +127,7 @@ public class ExtractedContentViewer implements DataContentViewer {
//if the node had artifacts in the lookup use them, other wise look up all credit card artifacts for the content.
Collection<? extends BlackboardArtifact> artifacts = nodeLookup.lookupAll(BlackboardArtifact.class);
artifacts = (artifacts == null || artifacts.isEmpty())
? content.getArtifacts(TSK_CREDIT_CARD_ACCOUNT)
? content.getArtifacts(TSK_ACCOUNT)
: artifacts;
/*
@ -140,7 +140,7 @@ public class ExtractedContentViewer implements DataContentViewer {
*/
for (BlackboardArtifact artifact : artifacts) {
try {
BlackboardAttribute solrIDAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID));
BlackboardAttribute solrIDAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID));
if (solrIDAttr != null) {
String valueString = solrIDAttr.getValueString();
if (StringUtils.isNotBlank(valueString)) {
@ -148,7 +148,7 @@ public class ExtractedContentViewer implements DataContentViewer {
}
}
BlackboardAttribute keyWordAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER));
BlackboardAttribute keyWordAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (keyWordAttr != null) {
String valueString = keyWordAttr.getValueString();
if (StringUtils.isNotBlank(valueString)) {
@ -188,7 +188,7 @@ public class ExtractedContentViewer implements DataContentViewer {
* For keyword hit artifacts, add the text of the artifact that hit,
* not the hit artifact; otherwise add the text for the artifact.
*/
if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID() || artifact.getArtifactTypeID() == TSK_CREDIT_CARD_ACCOUNT.getTypeID()) {
if (artifact.getArtifactTypeID() == TSK_KEYWORD_HIT.getTypeID() || artifact.getArtifactTypeID() == TSK_ACCOUNT.getTypeID()) {
try {
BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_ARTIFACT_TYPE);
if (attribute != null) {
@ -296,7 +296,7 @@ public class ExtractedContentViewer implements DataContentViewer {
Collection<? extends BlackboardArtifact> artifacts = node.getLookup().lookupAll(BlackboardArtifact.class);
if (artifacts != null) {
for (BlackboardArtifact art : artifacts) {
if (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID()) {
if (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
return true;
}
}
@ -321,7 +321,7 @@ public class ExtractedContentViewer implements DataContentViewer {
if (art == null) {
return 4;
} else if (art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
|| art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID()) {
|| art.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
return 6;
} else {
return 4;

View File

@ -122,7 +122,7 @@ abstract class KeywordSearchList {
//CCN
List<Keyword> ccns = new ArrayList<>();
ccns.add(new Keyword(CCN_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER));
ccns.add(new Keyword(CCN_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
lockedLists.add("Credit Card Numbers");
addList("Credit Card Numbers", ccns, true, false, true);
}

View File

@ -34,8 +34,9 @@ import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.TermsResponse.Term;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.datamodel.Accounts;
import org.sleuthkit.autopsy.datamodel.CreditCards;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -52,8 +53,7 @@ final class TermComponentQuery implements KeywordSearchQuery {
private static final boolean DEBUG = Version.Type.DEVELOPMENT.equals(Version.getBuildType());
private static final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
private static final BlackboardAttribute.Type SOLR_DOCUMENT_ID_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID);
private static final BlackboardAttribute.Type ACCOUNT_NUMBER_TYPE = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER);
private static final BlackboardAttribute.Type KEYWORD_SEARCH_DOCUMENT_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID);
//TODO: move these regex and the luhn check to a new class, something like: CreditCardNumberValidator
/*
@ -186,8 +186,13 @@ final class TermComponentQuery implements KeywordSearchQuery {
Collection<BlackboardAttribute> attributes = new ArrayList<>();
try {
//if the keyword hit matched the credit card number keyword/regex...
if (keyword.getType() == ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER) {
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT);
if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
final BlackboardAttribute attr = new BlackboardAttribute(
new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE),
MODULE_NAME, Account.Type.CREDIT_CARD.name());
newArtifact.addAttribute(attr);
// make account artifact
//try to match it against the track 1 regex
Matcher matcher = TRACK1_PATTERN.matcher(hit.getSnippet());
@ -204,31 +209,31 @@ final class TermComponentQuery implements KeywordSearchQuery {
AbstractFile file = (AbstractFile) hit.getContent();
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
newArtifact.addAttribute(new BlackboardAttribute(SOLR_DOCUMENT_ID_TYPE, MODULE_NAME, hit.getSolrDocumentId()));
newArtifact.addAttribute(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
String ccn = newArtifact.getAttribute(ACCOUNT_NUMBER_TYPE).getValueString();
final int iin = Integer.parseInt(ccn.substring(0, 8));
String ccn = newArtifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER)).getValueString();
final int bin = Integer.parseInt(ccn.substring(0, 8));
Accounts.IINInfo iinInfo = Accounts.getIINInfo(iin);
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (iinInfo != null) {
iinInfo.getScheme().ifPresent(scheme
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_SCHEME, scheme));
iinInfo.getCardType().ifPresent(cardType
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_PAYMENT_CARD_TYPE, cardType));
iinInfo.getBrand().ifPresent(brand
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BRAND, brand));
iinInfo.getBankName().ifPresent(bankName
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CARD_SCHEME, scheme));
binInfo.getCardType().ifPresent(cardType
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CARD_TYPE, cardType));
binInfo.getBrand().ifPresent(brand
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BRAND_NAME, brand));
binInfo.getBankName().ifPresent(bankName
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BANK_NAME, bankName));
iinInfo.getBankPhoneNumber().ifPresent(phoneNumber
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, phoneNumber));
iinInfo.getBankURL().ifPresent(url
binInfo.getBankURL().ifPresent(url
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_URL, url));
iinInfo.getCountry().ifPresent(country
binInfo.getCountry().ifPresent(country
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_COUNTRY, country));
iinInfo.getBankCity().ifPresent(city
binInfo.getBankCity().ifPresent(city
-> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CITY, city));
}
} else {
@ -323,7 +328,7 @@ final class TermComponentQuery implements KeywordSearchQuery {
for (Term term : terms) {
final String termStr = KeywordSearchUtil.escapeLuceneQuery(term.getTerm());
if (keyword.getType() == ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER) {
if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
//If the keyword is a credit card number, pass it through luhn validator
Matcher matcher = CCN_PATTERN.matcher(term.getTerm());
matcher.find();
@ -383,7 +388,7 @@ final class TermComponentQuery implements KeywordSearchQuery {
BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrType);
if (artifact.getAttribute(type) == null) {
String value = matcher.group(groupName);
if (attrType.equals(ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER)) {
if (attrType.equals(ATTRIBUTE_TYPE.TSK_CARD_NUMBER)) {
value = CharMatcher.anyOf(" -").removeFrom(value);
}
if (StringUtils.isNotBlank(value)) {
@ -404,11 +409,11 @@ final class TermComponentQuery implements KeywordSearchQuery {
*/
static private void parseTrack2Data(BlackboardArtifact artifact, Matcher matcher) throws IllegalArgumentException, TskCoreException {
//try to add all the attrributes common to track 1 and 2
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER, "accountNumber", matcher);
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_EXPIRATION, "expiration", matcher);
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_SERVICE_CODE, "serviceCode", matcher);
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_DISCRETIONARY, "discretionary", matcher);
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_LRC, "LRC", matcher);
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_NUMBER, "accountNumber", matcher);
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_EXPIRATION, "expiration", matcher);
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_SERVICE_CODE, "serviceCode", matcher);
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_DISCRETIONARY, "discretionary", matcher);
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CARD_LRC, "LRC", matcher);
}