Merge remote-tracking branch 'upstream/develop' into 6108-relocate-cr-upgrade

This commit is contained in:
Richard Cordovano 2020-03-20 13:13:57 -04:00
commit 8d29da20a3
20 changed files with 572 additions and 304 deletions

View File

@ -294,8 +294,9 @@ public class CorrelationAttributeInstance implements Serializable {
// Create Correlation Types for Accounts. // Create Correlation Types for Accounts.
int correlationTypeId = ADDITIONAL_TYPES_BASE_ID; int correlationTypeId = ADDITIONAL_TYPES_BASE_ID;
for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) { for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) {
// Skip Device account type - we dont want to correlate on those.
// Skip Phone and Email accounts as there are already Correlation types defined for those. // Skip Phone and Email accounts as there are already Correlation types defined for those.
if (type != Account.Type.EMAIL && type != Account.Type.PHONE) { if (type != Account.Type.DEVICE && type != Account.Type.EMAIL && type != Account.Type.PHONE) {
defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(correlationTypeId, type.getDisplayName(), type.getTypeName().toLowerCase() + "_acct", true, true)); //NON-NLS defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(correlationTypeId, type.getDisplayName(), type.getTypeName().toLowerCase() + "_acct", true, true)); //NON-NLS
correlationTypeId++; correlationTypeId++;
} }

View File

@ -27,6 +27,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
@ -185,24 +186,28 @@ public class CorrelationAttributeUtil {
BlackboardAttribute accountTypeAttribute = acctArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)); BlackboardAttribute accountTypeAttribute = acctArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE));
String accountTypeStr = accountTypeAttribute.getValueString(); String accountTypeStr = accountTypeAttribute.getValueString();
// Get the corresponding CentralRepoAccountType from the database. // do not create any correlation attribute instance for a Device account
CentralRepoAccountType crAccountType = CentralRepository.getInstance().getAccountTypeByName(accountTypeStr); if (Account.Type.DEVICE.getTypeName().equalsIgnoreCase(accountTypeStr) == false) {
int corrTypeId = crAccountType.getCorrelationTypeId(); // Get the corresponding CentralRepoAccountType from the database.
CorrelationAttributeInstance.Type corrType = CentralRepository.getInstance().getCorrelationTypeById(corrTypeId); CentralRepoAccountType crAccountType = CentralRepository.getInstance().getAccountTypeByName(accountTypeStr);
// Get the account identifier int corrTypeId = crAccountType.getCorrelationTypeId();
BlackboardAttribute accountIdAttribute = acctArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID)); CorrelationAttributeInstance.Type corrType = CentralRepository.getInstance().getCorrelationTypeById(corrTypeId);
String accountIdStr = accountIdAttribute.getValueString();
// add/get the account and get its accountId. // Get the account identifier
CentralRepoAccount crAccount = CentralRepository.getInstance().getOrCreateAccount(crAccountType, accountIdStr); BlackboardAttribute accountIdAttribute = acctArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID));
String accountIdStr = accountIdAttribute.getValueString();
CorrelationAttributeInstance corrAttr = makeCorrAttr(acctArtifact, corrType, accountIdStr); // add/get the account and get its accountId.
if (corrAttr != null) { CentralRepoAccount crAccount = CentralRepository.getInstance().getOrCreateAccount(crAccountType, accountIdStr);
// set the account_id in correlation attribute
corrAttr.setAccountId(crAccount.getAccountId()); CorrelationAttributeInstance corrAttr = makeCorrAttr(acctArtifact, corrType, accountIdStr);
corrAttrInstances.add(corrAttr); if (corrAttr != null) {
// set the account_id in correlation attribute
corrAttr.setAccountId(crAccount.getAccountId());
corrAttrInstances.add(corrAttr);
}
} }
} }

View File

@ -200,7 +200,7 @@ public class RdbmsCentralRepoFactory {
result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn)
&& CentralRepoDbUtil.insertDefaultOrganization(conn) && && CentralRepoDbUtil.insertDefaultOrganization(conn) &&
insertDefaultAccountsTablesContent(conn); RdbmsCentralRepoFactory.insertDefaultAccountsTablesContent(conn, selectedPlatform );
// @TODO: uncomment when ready to create/populate persona tables // @TODO: uncomment when ready to create/populate persona tables
// && insertDefaultPersonaTablesContent(conn); // && insertDefaultPersonaTablesContent(conn);
@ -798,33 +798,6 @@ public class RdbmsCentralRepoFactory {
} }
/**
* Inserts the default content in accounts related tables.
*
* @param conn Database connection to use.
*
* @return True if success, false otherwise.
*/
private boolean insertDefaultAccountsTablesContent(Connection conn) {
try (Statement stmt = conn.createStatement()) {
// Populate the account_types table
for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) {
int correlationTypeId = getCorrelationTypeIdForAccountType(conn, type);
if (correlationTypeId > 0) {
String sqlString = String.format("INSERT INTO account_types (type_name, display_name, correlation_type_id) VALUES ('%s', '%s', %d)" + getOnConflictDoNothingClause(selectedPlatform),
type.getTypeName(), type.getDisplayName(), correlationTypeId);
stmt.execute(sqlString);
}
}
} catch (SQLException ex) {
LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in Accounts tables."), ex);
return false;
}
return true;
}
/** /**
* Inserts the default content in persona related tables. * Inserts the default content in persona related tables.
* *
@ -870,11 +843,13 @@ public class RdbmsCentralRepoFactory {
// Populate the account_types table // Populate the account_types table
for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) { for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) {
int correlationTypeId = getCorrelationTypeIdForAccountType(conn, type); if (type != Account.Type.DEVICE) {
if (correlationTypeId > 0) { int correlationTypeId = getCorrelationTypeIdForAccountType(conn, type);
String sqlString = String.format("INSERT INTO account_types (type_name, display_name, correlation_type_id) VALUES ('%s', '%s', %d)" + getOnConflictDoNothingClause(selectedPlatform), if (correlationTypeId > 0) {
type.getTypeName(), type.getDisplayName(), correlationTypeId); String sqlString = String.format("INSERT INTO account_types (type_name, display_name, correlation_type_id) VALUES ('%s', '%s', %d)" + getOnConflictDoNothingClause(selectedPlatform),
stmt.execute(sqlString); type.getTypeName(), type.getDisplayName(), correlationTypeId);
stmt.execute(sqlString);
}
} }
} }

View File

@ -24,6 +24,7 @@ import java.awt.Cursor;
import java.awt.HeadlessException; import java.awt.HeadlessException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -31,14 +32,15 @@ import java.util.logging.Level;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import org.netbeans.spi.options.OptionsPanelController; import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
@ -65,18 +67,18 @@ public class EamDbSettingsDialog extends JDialog {
/** /**
* This class handles displaying and rendering drop down menu for database choices in central repo. * This class handles displaying and rendering drop down menu for database choices in central repo.
*/ */
private class DbChoiceRenderer extends BasicComboBoxRenderer { private class DbChoiceRenderer extends JLabel implements ListCellRenderer<CentralRepoDbChoice>, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public Component getListCellRendererComponent(JList list, Object value, @Override
public Component getListCellRendererComponent(
JList<? extends CentralRepoDbChoice> list, CentralRepoDbChoice value,
int index, boolean isSelected, boolean cellHasFocus) { int index, boolean isSelected, boolean cellHasFocus) {
CentralRepoDbChoice item = (CentralRepoDbChoice) value;
// disable cell if it is the db connection from multi user settings // disable cell if it is the db connection from multi user settings
// and that option is not enabled in multi user settings // and that option is not enabled in multi user settings
setText(item.getTitle()); setText(value.getTitle());
setEnabled(isDbChoiceSelectable(item)); setEnabled(isDbChoiceSelectable(value));
return this; return this;
} }
} }
@ -145,9 +147,7 @@ public class EamDbSettingsDialog extends JDialog {
CentralRepoDbChoice.DB_CHOICES[0] : CentralRepoDbChoice.DB_CHOICES[0] :
initialMenuItem; initialMenuItem;
// set the renderer so item is unselectable if inappropriate
cbDatabaseType.setRenderer(DB_CHOICE_RENDERER); cbDatabaseType.setRenderer(DB_CHOICE_RENDERER);
changeDbSelection(toSelect); changeDbSelection(toSelect);
} }

View File

@ -691,9 +691,9 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
enableButtonSubComponents(cbUseCentralRepo.isSelected()); enableButtonSubComponents(cbUseCentralRepo.isSelected());
} else { } else {
load(); load();
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && !caseIsOpen);
} }
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && !caseIsOpen);
} }
/** /**

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
@ -28,7 +29,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
@ -66,6 +66,7 @@ import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.texttranslation.utils.FileNameTranslationUtil;
/** /**
* An abstract node that encapsulates AbstractFile data * An abstract node that encapsulates AbstractFile data
@ -101,8 +102,8 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
this.content.getUniquePath(); this.content.getUniquePath();
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Failed attempt to cache the " logger.log(Level.SEVERE, String.format("Failed attempt to cache the "
+ "unique path of the abstract file instance. Name: %s (objID=%d)", + "unique path of the abstract file instance. Name: %s (objID=%d)",
this.content.getName(), this.content.getId()), ex); this.content.getName(), this.content.getId()), ex);
} }
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) { if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
@ -490,39 +491,18 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
} }
/** /**
* Translates this nodes content name. Doesn't attempt translation if the * Translates the name of the file this node represents. An empty string
* name is in english or if there is now translation service available. * will be returned if the translation fails for any reason.
*
* @return The translated file name or the empty string.
*/ */
String getTranslatedFileName() { String getTranslatedFileName() {
//If already in complete English, don't translate. try {
if (content.getName().matches("^\\p{ASCII}+$")) { return FileNameTranslationUtil.translate(content.getName());
} catch (NoServiceProviderException | TranslationException ex) {
logger.log(Level.WARNING, MessageFormat.format("Error translating file name (objID={0}))", content.getId()), ex);
return ""; return "";
} }
TextTranslationService tts = TextTranslationService.getInstance();
if (tts.hasProvider()) {
//Seperate out the base and ext from the contents file name.
String base = FilenameUtils.getBaseName(content.getName());
try {
String translation = tts.translate(base);
String ext = FilenameUtils.getExtension(content.getName());
//If we have no extension, then we shouldn't add the .
String extensionDelimiter = (ext.isEmpty()) ? "" : ".";
//Talk directly to this nodes pcl, fire an update when the translation
//is complete.
if (!translation.isEmpty()) {
return translation + extensionDelimiter + ext;
}
} catch (NoServiceProviderException noServiceEx) {
logger.log(Level.WARNING, "Translate unsuccessful because no TextTranslator "
+ "implementation was provided.", noServiceEx.getMessage());
} catch (TranslationException noTranslationEx) {
logger.log(Level.WARNING, "Could not successfully translate file name "
+ content.getName(), noTranslationEx.getMessage());
}
}
return "";
} }
/** /**

View File

@ -76,6 +76,9 @@ import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
/** /**
* A BlackboardArtifactNode is an AbstractNode implementation that can be used * A BlackboardArtifactNode is an AbstractNode implementation that can be used
@ -124,7 +127,8 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
}; };
private final BlackboardArtifact artifact; private final BlackboardArtifact artifact;
private Content srcContent; // May be null. private Content srcContent;
private volatile String translatedSourceName;
/* /*
* A method has been provided to allow the injection of properties into this * A method has been provided to allow the injection of properties into this
@ -133,7 +137,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
*/ */
private List<NodeProperty<? extends Object>> customProperties; private List<NodeProperty<? extends Object>> customProperties;
private final PropertyChangeListener appEventListener = new PropertyChangeListener() { private final PropertyChangeListener listener = new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
@ -148,25 +152,19 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
updateSheet(); updateSheet();
} }
} else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) { } else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
if (srcContent != null) { ContentTagAddedEvent event = (ContentTagAddedEvent) evt;
ContentTagAddedEvent event = (ContentTagAddedEvent) evt; if (event.getAddedTag().getContent().equals(srcContent)) {
if (event.getAddedTag().getContent().equals(srcContent)) { updateSheet();
updateSheet();
}
} }
} else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) { } else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
if (srcContent != null) { ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt;
ContentTagDeletedEvent event = (ContentTagDeletedEvent) evt; if (event.getDeletedTagInfo().getContentID() == srcContent.getId()) {
if (event.getDeletedTagInfo().getContentID() == srcContent.getId()) { updateSheet();
updateSheet();
}
} }
} else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) { } else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) {
if (srcContent != null) { CommentChangedEvent event = (CommentChangedEvent) evt;
CommentChangedEvent event = (CommentChangedEvent) evt; if (event.getContentID() == srcContent.getId()) {
if (event.getContentID() == srcContent.getId()) { updateSheet();
updateSheet();
}
} }
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
if (evt.getNewValue() == null) { if (evt.getNewValue() == null) {
@ -179,14 +177,41 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
} else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString()) && !UserPreferences.getHideSCOColumns()) { } else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString()) && !UserPreferences.getHideSCOColumns()) {
SCOData scoData = (SCOData) evt.getNewValue(); SCOData scoData = (SCOData) evt.getNewValue();
if (scoData.getScoreAndDescription() != null) { if (scoData.getScoreAndDescription() != null) {
updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft())); updateSheet(new NodeProperty<>(
Bundle.BlackboardArtifactNode_createSheet_score_name(),
Bundle.BlackboardArtifactNode_createSheet_score_displayName(),
scoData.getScoreAndDescription().getRight(),
scoData.getScoreAndDescription().getLeft()));
} }
if (scoData.getComment() != null) { if (scoData.getComment() != null) {
updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, scoData.getComment())); updateSheet(new NodeProperty<>(
Bundle.BlackboardArtifactNode_createSheet_comment_name(),
Bundle.BlackboardArtifactNode_createSheet_comment_displayName(),
NO_DESCR, scoData.getComment()));
} }
if (scoData.getCountAndDescription() != null) { if (scoData.getCountAndDescription() != null) {
updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft())); updateSheet(new NodeProperty<>(
Bundle.BlackboardArtifactNode_createSheet_count_name(),
Bundle.BlackboardArtifactNode_createSheet_count_displayName(),
scoData.getCountAndDescription().getRight(),
scoData.getCountAndDescription().getLeft()));
} }
} else if (eventType.equals(FileNameTransTask.getPropertyName())) {
/*
* Replace the value of the Source File property with the
* translated name via setDisplayName (see note in createSheet),
* and put the untranslated name in the Original Name property
* and in the tooltip.
*/
String originalName = evt.getOldValue().toString();
translatedSourceName = evt.getNewValue().toString();
setDisplayName(translatedSourceName);
setShortDescription(originalName);
updateSheet(new NodeProperty<>(
Bundle.BlackboardArtifactNode_createSheet_srcFile_origName(),
Bundle.BlackboardArtifactNode_createSheet_srcFile_origDisplayName(),
NO_DESCR,
originalName));
} }
} }
}; };
@ -198,7 +223,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* listener held by event publishers prevents garbage collection of this * listener held by event publishers prevents garbage collection of this
* node. * node.
*/ */
private final PropertyChangeListener weakAppEventListener = WeakListeners.propertyChange(appEventListener, null); private final PropertyChangeListener weakListener = WeakListeners.propertyChange(listener, null);
/** /**
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that * Constructs a BlackboardArtifactNode, an AbstractNode implementation that
@ -207,7 +232,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* @param artifact The artifact to represent. * @param artifact The artifact to represent.
* @param iconPath The path to the icon for the artifact type. * @param iconPath The path to the icon for the artifact type.
*/ */
@NbBundle.Messages({"# {0} - artifactDisplayName", "BlackboardArtifactNode.displayName.artifact={0} Artifact"})
public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) { public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
super(artifact, createLookup(artifact)); super(artifact, createLookup(artifact));
this.artifact = artifact; this.artifact = artifact;
@ -218,20 +242,25 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
/* /*
* Calling this getter causes the unique path of the source * Calling this getter causes the unique path of the source
* content to be cached in the Content object. This is * content to be cached in the Content object. This is
* advantageous if this node is constructed in a background * advantageous as long as this node is constructed in a
* thread instead of a UI thread. * background thread instead of a UI thread.
*/ */
srcContent.getUniquePath(); srcContent.getUniquePath();
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting the unique path of the source content (artifact objID={0})", artifact.getId()), ex); logger.log(Level.WARNING, MessageFormat.format("Error getting the unique path of the source content (artifact objID={0})", artifact.getId()), ex);
} }
break; break;
} }
} }
if (srcContent == null) {
throw new IllegalArgumentException(MessageFormat.format("Artifact missing source content (artifact objID={0})", artifact));
}
setName(Long.toString(artifact.getArtifactID())); setName(Long.toString(artifact.getArtifactID()));
setDisplayName(Bundle.BlackboardArtifactNode_displayName_artifact(artifact.getDisplayName())); String displayName = srcContent.getName();
setDisplayName(displayName);
setShortDescription(displayName);
setIconBaseWithExtension(iconPath); setIconBaseWithExtension(iconPath);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakAppEventListener); Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakListener);
} }
/** /**
@ -286,7 +315,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* Unregisters this node's application event listener. * Unregisters this node's application event listener.
*/ */
private void unregisterListener() { private void unregisterListener() {
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakAppEventListener); Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakListener);
} }
/** /**
@ -327,13 +356,15 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting linked file of artifact (artifact objID={0})", artifact.getId()), ex); //NON-NLS logger.log(Level.SEVERE, MessageFormat.format("Error getting linked file of artifact (artifact objID={0})", artifact.getId()), ex); //NON-NLS
} }
/* /*
* If the source content of the artifact represented by this node is a * If the source content of the artifact represented by this node is a
* file, add an action to view the file in the data source tree. * file, add an action to view the file in the data source tree.
*/ */
AbstractFile file = getLookup().lookup(AbstractFile.class); AbstractFile file = getLookup().lookup(AbstractFile.class
);
if (null != file) { if (null != file) {
actionsList.add(ViewFileInTimelineAction.createViewSourceFileAction(file)); actionsList.add(ViewFileInTimelineAction.createViewSourceFileAction(file));
} }
@ -348,14 +379,14 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* @return The source content name. * @return The source content name.
*/ */
public String getSourceName() { public String getSourceName() {
String name = ""; return srcContent.getName();
if (srcContent != null) {
name = srcContent.getName();
}
return name;
} }
@NbBundle.Messages({ @NbBundle.Messages({
"BlackboardArtifactNode.createSheet.srcFile.name=Source File",
"BlackboardArtifactNode.createSheet.srcFile.displayName=Source File",
"BlackboardArtifactNode.createSheet.srcFile.origName=Original Name",
"BlackboardArtifactNode.createSheet.srcFile.origDisplayName=Original Name",
"BlackboardArtifactNode.createSheet.artifactType.displayName=Result Type", "BlackboardArtifactNode.createSheet.artifactType.displayName=Result Type",
"BlackboardArtifactNode.createSheet.artifactType.name=Result Type", "BlackboardArtifactNode.createSheet.artifactType.name=Result Type",
"BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details", "BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details",
@ -381,12 +412,34 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
/* /*
* Add the name of the source content of the artifact represented by * Add the name of the source content of the artifact represented by
* this node to the sheet. * this node to the sheet. The value of this property is the same as the
* display name of the node and this a "special" property that displays
* the node's icon as well as the display name.
*/ */
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.displayName"), Bundle.BlackboardArtifactNode_createSheet_srcFile_name(),
Bundle.BlackboardArtifactNode_createSheet_srcFile_displayName(),
NO_DESCR, NO_DESCR,
this.getSourceName())); getDisplayName()));
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
/*
* If machine translation is configured, add the original name of
* the of the source content of the artifact represented by this
* node to the sheet.
*/
sheetSet.put(new NodeProperty<>(
Bundle.BlackboardArtifactNode_createSheet_srcFile_origName(),
Bundle.BlackboardArtifactNode_createSheet_srcFile_origDisplayName(),
NO_DESCR,
translatedSourceName != null ? srcContent.getName() : ""));
if (translatedSourceName == null) {
/*
* NOTE: The task makes its own weak reference to the listener.
*/
new FileNameTransTask(srcContent.getName(), this, listener).submit();
}
}
if (!UserPreferences.getHideSCOColumns()) { if (!UserPreferences.getHideSCOColumns()) {
/* /*
@ -396,12 +449,24 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* will fire a PropertyChangeEvent when the computation is completed * will fire a PropertyChangeEvent when the computation is completed
* and this node's PropertyChangeListener will update the sheet. * and this node's PropertyChangeListener will update the sheet.
*/ */
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), VALUE_LOADING, "")); sheetSet.put(new NodeProperty<>(
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), VALUE_LOADING, "")); Bundle.BlackboardArtifactNode_createSheet_score_name(),
Bundle.BlackboardArtifactNode_createSheet_score_displayName(),
VALUE_LOADING,
""));
sheetSet.put(new NodeProperty<>(
Bundle.BlackboardArtifactNode_createSheet_comment_name(),
Bundle.BlackboardArtifactNode_createSheet_comment_displayName(),
VALUE_LOADING,
""));
if (CentralRepository.isEnabled()) { if (CentralRepository.isEnabled()) {
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), VALUE_LOADING, "")); sheetSet.put(new NodeProperty<>(
Bundle.BlackboardArtifactNode_createSheet_count_name(),
Bundle.BlackboardArtifactNode_createSheet_count_displayName(),
VALUE_LOADING,
""));
} }
backgroundTasksPool.submit(new GetSCOTask(new WeakReference<>(this), weakAppEventListener)); backgroundTasksPool.submit(new GetSCOTask(new WeakReference<>(this), weakListener));
} }
/* /*
@ -414,11 +479,13 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
if (attribute != null) { if (attribute != null) {
BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.displayName"),
NO_DESCR, NO_DESCR,
associatedArtifact.getDisplayName())); associatedArtifact.getDisplayName()));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.displayName"),
NO_DESCR, NO_DESCR,
associatedArtifact.getShortDescription())); associatedArtifact.getShortDescription()));
@ -459,15 +526,17 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) { if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
String ext = ""; //NON-NLS String ext = ""; //NON-NLS
String actualMimeType = ""; //NON-NLS String actualMimeType = ""; //NON-NLS
if (srcContent != null && srcContent instanceof AbstractFile) { if (srcContent instanceof AbstractFile) {
AbstractFile file = (AbstractFile) srcContent; AbstractFile file = (AbstractFile) srcContent;
ext = file.getNameExtension(); ext = file.getNameExtension();
actualMimeType = file.getMIMEType(); actualMimeType = file.getMIMEType();
if (actualMimeType == null) { if (actualMimeType == null) {
actualMimeType = ""; //NON-NLS actualMimeType = ""; //NON-NLS
} }
} }
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.displayName"),
NO_DESCR, NO_DESCR,
ext)); ext));
@ -484,12 +553,11 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
*/ */
if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) { if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
String sourcePath = ""; //NON-NLS String sourcePath = ""; //NON-NLS
if (srcContent != null) { try {
try { sourcePath = srcContent.getUniquePath();
sourcePath = srcContent.getUniquePath(); } catch (TskCoreException ex) {
} catch (TskCoreException ex) { logger.log(Level.SEVERE, MessageFormat.format("Error getting unique path of source content (artifact objID={0})", artifact.getId()), ex); //NON-NLS
logger.log(Level.SEVERE, MessageFormat.format("Error getting unique path of source content (artifact objID={0})", artifact.getId()), ex); //NON-NLS
}
} }
if (sourcePath.isEmpty() == false) { if (sourcePath.isEmpty() == false) {
@ -506,45 +574,50 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* sheet. Otherwise, add the data source to the sheet. * sheet. Otherwise, add the data source to the sheet.
*/ */
if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) { if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
AbstractFile file = srcContent != null && srcContent instanceof AbstractFile ? (AbstractFile) srcContent : null; AbstractFile file = srcContent instanceof AbstractFile ? (AbstractFile) srcContent : null;
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"),
"", "",
file == null ? "" : ContentUtils.getStringTime(file.getMtime(), file))); file == null ? "" : ContentUtils.getStringTime(file.getMtime(), file)));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"),
"", "",
file == null ? "" : ContentUtils.getStringTime(file.getCtime(), file))); file == null ? "" : ContentUtils.getStringTime(file.getCtime(), file)));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"),
"", "",
file == null ? "" : ContentUtils.getStringTime(file.getAtime(), file))); file == null ? "" : ContentUtils.getStringTime(file.getAtime(), file)));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"),
"", "",
file == null ? "" : ContentUtils.getStringTime(file.getCrtime(), file))); file == null ? "" : ContentUtils.getStringTime(file.getCrtime(), file)));
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"),
"", "",
file == null ? "" : file.getSize())); file == null ? "" : file.getSize()));
sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_artifactMD5_name(), sheetSet.put(new NodeProperty<>(
Bundle.BlackboardArtifactNode_createSheet_artifactMD5_name(),
Bundle.BlackboardArtifactNode_createSheet_artifactMD5_displayName(), Bundle.BlackboardArtifactNode_createSheet_artifactMD5_displayName(),
"", "",
file == null ? "" : StringUtils.defaultString(file.getMd5Hash()))); file == null ? "" : StringUtils.defaultString(file.getMd5Hash())));
} }
} else { } else {
String dataSourceStr = ""; String dataSourceStr = "";
if (srcContent != null) { try {
try { Content dataSource = srcContent.getDataSource();
Content dataSource = srcContent.getDataSource(); if (dataSource != null) {
if (dataSource != null) { dataSourceStr = dataSource.getName();
dataSourceStr = dataSource.getName(); } else {
} else { dataSourceStr = getRootAncestorName();
dataSourceStr = getRootAncestorName();
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting source data source name (artifact objID={0})", artifact.getId()), ex); //NON-NLS
} }
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting source data source name (artifact objID={0})", artifact.getId()), ex); //NON-NLS
} }
if (dataSourceStr.isEmpty() == false) { if (dataSourceStr.isEmpty() == false) {
@ -563,24 +636,27 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) { if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) {
long size = 0; long size = 0;
String path = ""; //NON-NLS String path = ""; //NON-NLS
if (srcContent != null && srcContent instanceof AbstractFile) { if (srcContent instanceof AbstractFile) {
AbstractFile af = (AbstractFile) srcContent; AbstractFile af = (AbstractFile) srcContent;
size = af.getSize(); size = af.getSize();
try { try {
path = af.getUniquePath(); path = af.getUniquePath();
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
path = af.getParentPath(); path = af.getParentPath();
} }
} }
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.name"), sheetSet.put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.name"),
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.displayName"),
NO_DESCR, NO_DESCR,
size)); size));
sheetSet.put(new NodeProperty<>( sheetSet
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.name"), .put(new NodeProperty<>(
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.displayName"), NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.name"),
NO_DESCR, NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.displayName"),
path)); NO_DESCR,
path));
} }
return sheet; return sheet;
@ -597,9 +673,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
List<Tag> tags = new ArrayList<>(); List<Tag> tags = new ArrayList<>();
try { try {
tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact)); tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact));
if (srcContent != null) { tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(srcContent));
tags.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(srcContent));
}
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting tags for artifact and its source content (artifact objID={0})", artifact.getId()), ex); logger.log(Level.SEVERE, MessageFormat.format("Error getting tags for artifact and its source content (artifact objID={0})", artifact.getId()), ex);
} }
@ -617,7 +691,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
@Override @Override
protected final CorrelationAttributeInstance getCorrelationAttributeInstance() { protected final CorrelationAttributeInstance getCorrelationAttributeInstance() {
CorrelationAttributeInstance correlationAttribute = null; CorrelationAttributeInstance correlationAttribute = null;
if (srcContent != null && CentralRepository.isEnabled() && srcContent instanceof AbstractFile) { if (CentralRepository.isEnabled() && srcContent instanceof AbstractFile) {
correlationAttribute = CorrelationAttributeUtil.getCorrAttrForFile((AbstractFile) srcContent); correlationAttribute = CorrelationAttributeUtil.getCorrAttrForFile((AbstractFile) srcContent);
} }
return correlationAttribute; return correlationAttribute;
@ -695,7 +769,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
*/ */
Score score = Score.NO_SCORE; Score score = Score.NO_SCORE;
String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description(); String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description();
if (srcContent != null && srcContent instanceof AbstractFile) { if (srcContent instanceof AbstractFile) {
if (((AbstractFile) srcContent).getKnown() == TskData.FileKnown.BAD) { if (((AbstractFile) srcContent).getKnown() == TskData.FileKnown.BAD) {
score = Score.NOTABLE_SCORE; score = Score.NOTABLE_SCORE;
description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description(); description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
@ -725,7 +799,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
/* /*
* Is the artifact's source content notable? * Is the artifact's source content notable?
*/ */
if (score == Score.NO_SCORE && srcContent != null) { if (score == Score.NO_SCORE) {
try { try {
if (!srcContent.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT).isEmpty()) { if (!srcContent.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT).isEmpty()) {
score = Score.INTERESTING_SCORE; score = Score.INTERESTING_SCORE;
@ -814,7 +888,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
parentName = parent.getName(); parentName = parent.getName();
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, MessageFormat.format("Error getting root ancestor name for source content (artifact objID={0})", artifact.getId())); //NON-NLS logger.log(Level.SEVERE, MessageFormat.format("Error getting root ancestor name for source content (artifact objID={0})", artifact.getId()), ex); //NON-NLS
return ""; return "";
} }
return parentName; return parentName;
@ -1036,8 +1110,8 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* @param attribute The correlation attribute instance to use for the * @param attribute The correlation attribute instance to use for the
* central repository lookup. * central repository lookup.
* *
* @deprecated Do not use. The other occurrences property is now computed in a * @deprecated Do not use. The other occurrences property is now computed in
* background thread and added to the property sheet via property change * a background thread and added to the property sheet via property change
* event. * event.
*/ */
@NbBundle.Messages({"BlackboardArtifactNode.createSheet.comment.name=C", @NbBundle.Messages({"BlackboardArtifactNode.createSheet.comment.name=C",

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-2018 Basis Technology Corp. * Copyright 2013-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -24,13 +24,11 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.Action; import javax.swing.Action;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction; import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
@ -46,14 +44,14 @@ import static org.sleuthkit.autopsy.datamodel.Bundle.*;
* tag name nodes have tag type child nodes; tag type nodes are the parents of * tag name nodes have tag type child nodes; tag type nodes are the parents of
* either content or blackboard artifact tag nodes. * either content or blackboard artifact tag nodes.
*/ */
public class BlackboardArtifactTagNode extends DisplayableItemNode { public class BlackboardArtifactTagNode extends TagNode {
private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactTagNode.class.getName()); private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactTagNode.class.getName());
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/green-tag-icon-16.png"; //NON-NLS private static final String ICON_PATH = "org/sleuthkit/autopsy/images/green-tag-icon-16.png"; //NON-NLS
private final BlackboardArtifactTag tag; private final BlackboardArtifactTag tag;
public BlackboardArtifactTagNode(BlackboardArtifactTag tag) { public BlackboardArtifactTagNode(BlackboardArtifactTag tag) {
super(Children.LEAF, Lookups.fixed(tag, tag.getArtifact(), tag.getContent())); super(Lookups.fixed(tag, tag.getArtifact(), tag.getContent()), tag.getContent());
super.setName(tag.getContent().getName()); super.setName(tag.getContent().getName());
super.setDisplayName(tag.getContent().getName()); super.setDisplayName(tag.getContent().getName());
this.setIconBaseWithExtension(ICON_PATH); this.setIconBaseWithExtension(ICON_PATH);
@ -75,6 +73,7 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFile.text"), NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFile.text"),
"", "",
tag.getContent().getName())); tag.getContent().getName()));
addOriginalNameProp(properties);
String contentPath; String contentPath;
try { try {
contentPath = tag.getContent().getUniquePath(); contentPath = tag.getContent().getUniquePath();
@ -82,7 +81,6 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex); //NON-NLS Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex); //NON-NLS
contentPath = NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.unavail.text"); contentPath = NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.unavail.text");
} }
properties.put(new NodeProperty<>( properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"), NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"),
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"), NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"),
@ -146,11 +144,6 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
return visitor.visit(this); return visitor.visit(this);
} }
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override @Override
public String getItemType() { public String getItemType() {
return getClass().getName(); return getClass().getName();

View File

@ -11,8 +11,6 @@ ArtifactTypeNode.createSheet.childCnt.name=Child Count
ArtifactTypeNode.createSheet.childCnt.displayName=Child Count ArtifactTypeNode.createSheet.childCnt.displayName=Child Count
ArtifactTypeNode.createSheet.childCnt.desc=no description ArtifactTypeNode.createSheet.childCnt.desc=no description
BlackboardArtifactNode.noDesc.text=no description BlackboardArtifactNode.noDesc.text=no description
BlackboardArtifactNode.createSheet.srcFile.name=Source File
BlackboardArtifactNode.createSheet.srcFile.displayName=Source File
BlackboardArtifactNode.createSheet.ext.name=Extension BlackboardArtifactNode.createSheet.ext.name=Extension
BlackboardArtifactNode.createSheet.ext.displayName=Extension BlackboardArtifactNode.createSheet.ext.displayName=Extension
BlackboardArtifactNode.createSheet.mimeType.name=MIME Type BlackboardArtifactNode.createSheet.mimeType.name=MIME Type

View File

@ -74,10 +74,12 @@ BlackboardArtifactNode.createSheet.path.displayName=Path
BlackboardArtifactNode.createSheet.path.name=Path BlackboardArtifactNode.createSheet.path.name=Path
BlackboardArtifactNode.createSheet.score.displayName=S BlackboardArtifactNode.createSheet.score.displayName=S
BlackboardArtifactNode.createSheet.score.name=S BlackboardArtifactNode.createSheet.score.name=S
BlackboardArtifactNode.createSheet.srcFile.displayName=Source File
BlackboardArtifactNode.createSheet.srcFile.name=Source File
BlackboardArtifactNode.createSheet.srcFile.origDisplayName=Original Name
BlackboardArtifactNode.createSheet.srcFile.origName=Original Name
BlackboardArtifactNode.createSheet.taggedItem.description=Result or associated file has been tagged. BlackboardArtifactNode.createSheet.taggedItem.description=Result or associated file has been tagged.
BlackboardArtifactNode.createSheet.tags.displayName=Tags BlackboardArtifactNode.createSheet.tags.displayName=Tags
# {0} - artifactDisplayName
BlackboardArtifactNode.displayName.artifact={0} Artifact
BlackboardArtifactTagNode.createSheet.userName.text=User Name BlackboardArtifactTagNode.createSheet.userName.text=User Name
BlackboardArtifactTagNode.viewSourceArtifact.text=View Source Result BlackboardArtifactTagNode.viewSourceArtifact.text=View Source Result
Category.five=CAT-5: Non-pertinent Category.five=CAT-5: Non-pertinent
@ -88,6 +90,7 @@ Category.two=CAT-2: Child Exploitation (Non-Illegal/Age Difficult)
Category.zero=CAT-0: Uncategorized Category.zero=CAT-0: Uncategorized
ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash
ContentTagNode.createSheet.artifactMD5.name=MD5 Hash ContentTagNode.createSheet.artifactMD5.name=MD5 Hash
ContentTagNode.createSheet.origFileName=Original Name
ContentTagNode.createSheet.userName.text=User Name ContentTagNode.createSheet.userName.text=User Name
DeletedContent.allDelFilter.text=All DeletedContent.allDelFilter.text=All
DeletedContent.createSheet.filterType.desc=no description DeletedContent.createSheet.filterType.desc=no description
@ -175,8 +178,6 @@ ArtifactTypeNode.createSheet.childCnt.name=Child Count
ArtifactTypeNode.createSheet.childCnt.displayName=Child Count ArtifactTypeNode.createSheet.childCnt.displayName=Child Count
ArtifactTypeNode.createSheet.childCnt.desc=no description ArtifactTypeNode.createSheet.childCnt.desc=no description
BlackboardArtifactNode.noDesc.text=no description BlackboardArtifactNode.noDesc.text=no description
BlackboardArtifactNode.createSheet.srcFile.name=Source File
BlackboardArtifactNode.createSheet.srcFile.displayName=Source File
BlackboardArtifactNode.createSheet.ext.name=Extension BlackboardArtifactNode.createSheet.ext.name=Extension
BlackboardArtifactNode.createSheet.ext.displayName=Extension BlackboardArtifactNode.createSheet.ext.displayName=Extension
BlackboardArtifactNode.createSheet.mimeType.name=MIME Type BlackboardArtifactNode.createSheet.mimeType.name=MIME Type
@ -345,6 +346,8 @@ TagNameNode.bbArtTagTypeNodeKey.text=Result Tags
TagNameNode.bookmark.text=Bookmark TagNameNode.bookmark.text=Bookmark
TagNameNode.createSheet.name.name=Name TagNameNode.createSheet.name.name=Name
TagNameNode.createSheet.name.displayName=Name TagNameNode.createSheet.name.displayName=Name
TagNode.propertySheet.origName=Original Name
TagNode.propertySheet.origNameDisplayName=Original Name
TagsNode.displayName.text=Tags TagsNode.displayName.text=Tags
TagsNode.createSheet.name.name=Name TagsNode.createSheet.name.name=Name
TagsNode.createSheet.name.displayName=Name TagsNode.createSheet.name.displayName=Name

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-2016 Basis Technology Corp. * Copyright 2013-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -24,7 +24,6 @@ import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.Action; import javax.swing.Action;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
@ -39,18 +38,16 @@ import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Instances of this class wrap ContentTag objects. In the Autopsy presentation * Instances of this class wrap ContentTag objects. In the Autopsy presentation
* of the SleuthKit data model, they are leaf nodes of a tree consisting of * of the SleuthKit data model, they are leaf nodes of a tree consisting of
* content and blackboard artifact tags, grouped first by tag type, then by tag * content and artifact tags, grouped first by tag type, then by tag name.
* name.
*/ */
class ContentTagNode extends DisplayableItemNode { class ContentTagNode extends TagNode {
private static final Logger LOGGER = Logger.getLogger(ContentTagNode.class.getName()); private static final Logger LOGGER = Logger.getLogger(ContentTagNode.class.getName());
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png"; //NON-NLS private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png"; //NON-NLS
private final ContentTag tag; private final ContentTag tag;
public ContentTagNode(ContentTag tag) { ContentTagNode(ContentTag tag) {
super(Children.LEAF, Lookups.fixed(tag, tag.getContent())); super(Lookups.fixed(tag, tag.getContent()), tag.getContent());
super.setName(tag.getContent().getName()); super.setName(tag.getContent().getName());
super.setDisplayName(tag.getContent().getName()); super.setDisplayName(tag.getContent().getName());
this.setIconBaseWithExtension(ICON_PATH); this.setIconBaseWithExtension(ICON_PATH);
@ -58,6 +55,7 @@ class ContentTagNode extends DisplayableItemNode {
} }
@Messages({ @Messages({
"ContentTagNode.createSheet.origFileName=Original Name",
"ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash", "ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash",
"ContentTagNode.createSheet.artifactMD5.name=MD5 Hash", "ContentTagNode.createSheet.artifactMD5.name=MD5 Hash",
"ContentTagNode.createSheet.userName.text=User Name"}) "ContentTagNode.createSheet.userName.text=User Name"})
@ -79,15 +77,19 @@ class ContentTagNode extends DisplayableItemNode {
properties = Sheet.createPropertiesSet(); properties = Sheet.createPropertiesSet();
propertySheet.put(properties); propertySheet.put(properties);
} }
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.name"), properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.displayName"), NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.displayName"),
"", "",
content.getName())); content.getName()));
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.name"), addOriginalNameProp(properties);
properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.displayName"), NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.displayName"),
"", "",
contentPath)); contentPath));
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.name"), properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.displayName"), NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.displayName"),
"", "",
tag.getComment())); tag.getComment()));
@ -95,23 +97,28 @@ class ContentTagNode extends DisplayableItemNode {
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"), NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"),
"", "",
file != null ? ContentUtils.getStringTime(file.getMtime(), file) : "")); file != null ? ContentUtils.getStringTime(file.getMtime(), file) : ""));
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"), properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"), NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"),
"", "",
file != null ? ContentUtils.getStringTime(file.getCtime(), file) : "")); file != null ? ContentUtils.getStringTime(file.getCtime(), file) : ""));
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"), properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"), NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"),
"", "",
file != null ? ContentUtils.getStringTime(file.getAtime(), file) : "")); file != null ? ContentUtils.getStringTime(file.getAtime(), file) : ""));
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"), properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"), NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"),
"", "",
file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : "")); file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : ""));
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"), properties.put(new NodeProperty<>(
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"), NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"),
"", "",
content.getSize())); content.getSize()));
properties.put(new NodeProperty<>(Bundle.ContentTagNode_createSheet_artifactMD5_name(), properties.put(new NodeProperty<>(
Bundle.ContentTagNode_createSheet_artifactMD5_name(),
Bundle.ContentTagNode_createSheet_artifactMD5_displayName(), Bundle.ContentTagNode_createSheet_artifactMD5_displayName(),
"", "",
file != null ? StringUtils.defaultString(file.getMd5Hash()) : "")); file != null ? StringUtils.defaultString(file.getMd5Hash()) : ""));
@ -128,8 +135,7 @@ class ContentTagNode extends DisplayableItemNode {
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
actions.addAll(Arrays.asList(super.getActions(context))); actions.addAll(Arrays.asList(super.getActions(context)));
AbstractFile file = getLookup().lookup(AbstractFile.class AbstractFile file = getLookup().lookup(AbstractFile.class);
);
if (file != null) { if (file != null) {
actions.add(ViewFileInTimelineAction.createViewFileAction(file)); actions.add(ViewFileInTimelineAction.createViewFileAction(file));
} }
@ -144,13 +150,9 @@ class ContentTagNode extends DisplayableItemNode {
return visitor.visit(this); return visitor.visit(this);
} }
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override @Override
public String getItemType() { public String getItemType() {
return getClass().getName(); return getClass().getName();
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2012-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel;
import org.openide.nodes.AbstractNode; import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
@ -142,4 +143,26 @@ public abstract class DisplayableItemNode extends AbstractNode {
return selectedChildNodeInfo; return selectedChildNodeInfo;
} }
/**
* Updates the node property sheet by replacing existing properties with new
* properties with the same property name.
*
* @param newProps The replacement property objects.
*/
protected synchronized final void updatePropertySheet(NodeProperty<?>... newProps) {
Sheet currentSheet = this.getSheet();
Sheet.Set currentPropsSet = currentSheet.get(Sheet.PROPERTIES);
Property<?>[] currentProps = currentPropsSet.getProperties();
for (NodeProperty<?> newProp : newProps) {
for (int i = 0; i < currentProps.length; i++) {
if (currentProps[i].getName().equals(newProp.getName())) {
currentProps[i] = newProp;
}
}
}
currentPropsSet.put(currentProps);
currentSheet.put(currentPropsSet);
this.setSheet(currentSheet);
}
} }

View File

@ -0,0 +1,128 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020-2020 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;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import org.openide.nodes.Children;
import org.openide.nodes.Sheet;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.datamodel.Content;
/**
* An abstract superclass for a node that represents a tag, uses the name of a
* given Content object as its display name, and has a property sheet with an
* original name property when machine translation is enabled.
*
* The translation of the Content name is done in a background thread. The
* translated name is made the display name of the node and the untranslated
* name is put into both the original name property and into the node's tooltip.
*
* TODO (Jira-6174): Consider modifying this class to be able to use it more broadly
* within the Autopsy data model (i.e., AbstractNode suclasses). It's not really
* specific to a tag node.
*/
@NbBundle.Messages({
"TagNode.propertySheet.origName=Original Name",
"TagNode.propertySheet.origNameDisplayName=Original Name"
})
abstract class TagNode extends DisplayableItemNode {
private final static String ORIG_NAME_PROP_NAME = Bundle.TagNode_propertySheet_origName();
private final static String ORIG_NAME_PROP_DISPLAY_NAME = Bundle.TagNode_propertySheet_origNameDisplayName();
private final String originalName;
private volatile String translatedName;
/**
* An abstract superclass for a node that represents a tag, uses the name of
* a given Content object as its display name, and has a property sheet with
* an untranslated file name property when machine translation is enabled.
*
* @param lookup The Lookup of the node.
* @param content The Content to use for the node display name.
*/
TagNode(Lookup lookup, Content content) {
super(Children.LEAF, lookup);
originalName = content.getName();
}
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override
abstract public String getItemType();
@Override
abstract public <T> T accept(DisplayableItemNodeVisitor<T> visitor);
/**
* Adds an original name property to the node's property sheet and submits
* an original name translation task.
*
* The translation of the original name is done in a background thread. The
* translated name is made the display name of the node and the untranslated
* name is put into both the original name property and into the node's
* tooltip.
*
* @param properties The node's property sheet.
*/
protected void addOriginalNameProp(Sheet.Set properties) {
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
properties.put(new NodeProperty<>(
ORIG_NAME_PROP_NAME,
ORIG_NAME_PROP_DISPLAY_NAME,
"",
translatedName != null ? originalName : ""));
if (translatedName == null) {
new FileNameTransTask(originalName, this, new NameTranslationListener()).submit();
}
}
}
/**
* A listener for PropertyChangeEvents from a background task used to
* translate the original display name associated with the node.
*/
private class NameTranslationListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(FileNameTransTask.getPropertyName())) {
translatedName = evt.getNewValue().toString();
String originalName = evt.getOldValue().toString();
setDisplayName(translatedName);
setShortDescription(originalName);
updatePropertySheet(new NodeProperty<>(
ORIG_NAME_PROP_NAME,
ORIG_NAME_PROP_DISPLAY_NAME,
"",
originalName));
}
}
}
}

View File

@ -64,7 +64,7 @@ public abstract class AbstractNodePropertySheetTask<T extends AbstractNode> impl
* @return The Future of the task, may be used for task cancellation by * @return The Future of the task, may be used for task cancellation by
* calling Future.cancel(true). * calling Future.cancel(true).
*/ */
public static Future<?> submitTask(AbstractNodePropertySheetTask<?> task) { private static Future<?> submitTask(AbstractNodePropertySheetTask<?> task) {
return executor.submit(task); return executor.submit(task);
} }
@ -104,12 +104,22 @@ public abstract class AbstractNodePropertySheetTask<T extends AbstractNode> impl
* *
* @param node The AbstractNode. * @param node The AbstractNode.
* *
* @return The result of the computation as a PropertyChangeEvent. * @return The result of the computation as a PropertyChangeEvent, may be
* null.
*/ */
protected abstract PropertyChangeEvent computePropertyValue(T node) throws Exception; protected abstract PropertyChangeEvent computePropertyValue(T node) throws Exception;
/**
* Submits this task to the ExecutorService for the thread pool.
*
* @return The task's Future from the ExecutorService.
*/
public final Future<?> submit() {
return submitTask(this);
}
@Override @Override
final public void run() { public final void run() {
try { try {
T node = this.weakNodeRef.get(); T node = this.weakNodeRef.get();
PropertyChangeListener listener = this.weakListenerRef.get(); PropertyChangeListener listener = this.weakListenerRef.get();

View File

@ -0,0 +1,61 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.utils;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import org.openide.nodes.AbstractNode;
import org.sleuthkit.autopsy.texttranslation.utils.FileNameTranslationUtil;
/**
* An AbstractNodePropertySheetTask that translates a file name for an
* AbstractNode's property sheet.
*/
public class FileNameTransTask extends AbstractNodePropertySheetTask<AbstractNode> {
private final static String EVENT_SOURCE = FileNameTransTask.class.getName();
private final static String PROPERTY_NAME = EVENT_SOURCE + ".TranslatedFileName";
private final String fileName;
public static String getPropertyName() {
return PROPERTY_NAME;
}
/**
* Constructs an AbstractNodePropertySheetTask that translates a file name
* for an AbstractNode's property sheet. When the translation is complete, a
* PropertyChangeEvent will be fired to the node's PropertyChangeListener.
* Call getPropertyName() to identify the property.
*
* @param node The node.
* @param listener The node's PropertyChangeListener.
* @param fileName THe file name.
*/
public FileNameTransTask(String fileName, AbstractNode node, PropertyChangeListener listener) {
super(node, listener);
this.fileName = fileName;
}
@Override
protected PropertyChangeEvent computePropertyValue(AbstractNode node) throws Exception {
String translatedFileName = FileNameTranslationUtil.translate(fileName);
return translatedFileName.isEmpty() ? null : new PropertyChangeEvent(EVENT_SOURCE, PROPERTY_NAME, fileName, translatedFileName);
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2019 Basis Technology Corp. * Copyright 2012-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -187,27 +187,6 @@ public class DataResultFilterNode extends FilterNode {
return propertySets; return propertySets;
} }
/**
* Gets the display name for the wrapped node.
*
* OutlineView used in the DataResult table uses getDisplayName() to
* populate the first column, which is Source File.
*
* Hence this override to return the 'correct' displayName for the wrapped
* node.
*
* @return The display name for the node.
*/
@Override
public String getDisplayName() {
final Node orig = getOriginal();
String name = orig.getDisplayName();
if ((orig instanceof BlackboardArtifactNode)) {
name = ((BlackboardArtifactNode) orig).getSourceName();
}
return name;
}
/** /**
* Adds information about which child node of this node, if any, should be * Adds information about which child node of this node, if any, should be
* selected. Can be null. * selected. Can be null.

View File

@ -273,7 +273,6 @@ final class FileSearchData {
= new ImmutableSet.Builder<String>() = new ImmutableSet.Builder<String>()
.add("text/html", //NON-NLS .add("text/html", //NON-NLS
"text/csv", //NON-NLS "text/csv", //NON-NLS
"text/x-log", //NON-NLS
"application/rtf", //NON-NLS "application/rtf", //NON-NLS
"application/pdf", //NON-NLS "application/pdf", //NON-NLS
"application/xhtml+xml", //NON-NLS "application/xhtml+xml", //NON-NLS

View File

@ -0,0 +1,74 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020-2020 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.texttranslation.utils;
import org.apache.commons.io.FilenameUtils;
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.autopsy.texttranslation.TranslationException;
/**
* A utility to translate file names.
*/
public final class FileNameTranslationUtil {
/**
* Translates a file name using the configured machine translation service.
*
* @param fileName The file name.
*
* @return The translation of the file name.
*
* @throws NoServiceProviderException If machine translation is not
* configured.
* @throws TranslationException If there is an error doing the
* translation.
*/
public static String translate(String fileName) throws NoServiceProviderException, TranslationException {
/*
* Don't attempt translation if the characters of the file name are all
* ASCII chars.
*
* TODO (Jira-6175): This filter prevents translation of many
* non-English file names composed entirely of Latin chars.
*/
if (fileName.matches("^\\p{ASCII}+$")) {
return "";
}
TextTranslationService translator = TextTranslationService.getInstance();
String baseName = FilenameUtils.getBaseName(fileName);
String translation = translator.translate(baseName);
if (!translation.isEmpty()) {
String extension = FilenameUtils.getExtension(fileName);
if (!extension.isEmpty()) {
String extensionDelimiter = (extension.isEmpty()) ? "" : ".";
translation += extensionDelimiter + extension;
}
}
return translation;
}
/**
* Prevent instantiation of this utility class
*/
private FileNameTranslationUtil() {
}
}

View File

@ -95,7 +95,7 @@ class BrowserLocationAnalyzer(general.AndroidComponentAnalyzer):
longitude = Double.valueOf(resultSet.getString("longitude")) longitude = Double.valueOf(resultSet.getString("longitude"))
attributes = ArrayList() attributes = ArrayList()
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT) artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, general.MODULE_NAME, latitude)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, general.MODULE_NAME, latitude))
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, general.MODULE_NAME, longitude)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, general.MODULE_NAME, longitude))
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, timestamp)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, timestamp))

View File

@ -41,6 +41,7 @@ from org.sleuthkit.datamodel import TskCoreException
import traceback import traceback
import general import general
import struct
""" """
Parses cache files that Android maintains for Wifi and cell towers. Adds GPS points to blackboard. Parses cache files that Android maintains for Wifi and cell towers. Adds GPS points to blackboard.
@ -74,60 +75,24 @@ class CacheLocationAnalyzer(general.AndroidComponentAnalyzer):
def __findGeoLocationsInFile(self, file, abstractFile): def __findGeoLocationsInFile(self, file, abstractFile):
tempBytes = bytearray([0] * 2) # will temporarily hold bytes to be converted into the correct data types
try: try:
inputStream = FileInputStream(file) # code to parse the cache.wifi and cache.cell taken from https://forensics.spreitzenbarth.de/2011/10/28/decoding-cache-cell-and-cache-wifi-files/
cacheFile = open(str(file), 'rb')
inputStream.read(tempBytes) # version (version, entries) = struct.unpack('>hh', cacheFile.read(4))
i = 0
tempBytes = bytearray([0] * 2) while i < entries:
inputStream.read(tempBytes) # number of location entries key = cacheFile.read(struct.unpack('>h', cacheFile.read(2))[0])
(accuracy, confidence, latitude, longitude, readtime) = struct.unpack('>iiddQ', cacheFile.read(32))
iterations = BigInteger(tempBytes).intValue() timestamp = readtime/1000
i = i + 1
for i in range(iterations): # loop through every entry
tempBytes = bytearray([0] * 2)
inputStream.read(tempBytes)
tempBytes = bytearray([0])
inputStream.read(tempBytes)
while BigInteger(tempBytes).intValue() != 0: # pass through non important values until the start of accuracy(around 7-10 bytes)
if 0 > inputStream.read(tempBytes):
break # we've passed the end of the file, so stop
tempBytes = bytearray([0] * 3)
inputStream.read(tempBytes)
if BigInteger(tempBytes).intValue() <= 0: # This refers to a location that could not be calculated
tempBytes = bytearray([0] * 28) # read rest of the row's bytes
inputStream.read(tempBytes)
continue
accuracy = "" + BigInteger(tempBytes).intValue()
tempBytes = bytearray([0] * 4)
inputStream.read(tempBytes)
confidence = "" + BigInteger(tempBytes).intValue()
tempBytes = bytearray([0] * 8)
inputStream.read(tempBytes)
latitude = CacheLocationAnalyzer.toDouble(bytes)
tempBytes = bytearray([0] * 8)
inputStream.read(tempBytes)
longitude = CacheLocationAnalyzer.toDouble(bytes)
tempBytes = bytearray([0] * 8)
inputStream.read(tempBytes)
timestamp = BigInteger(tempBytes).longValue() / 1000
attributes = ArrayList() attributes = ArrayList()
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT) artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, AndroidAnalyzer.MODULE_NAME, latitude)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, general.MODULE_NAME, latitude))
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, AndroidAnalyzer.MODULE_NAME, longitude)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, general.MODULE_NAME, longitude))
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, AndroidModuleFactorymodule.Name, timestamp)) attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, timestamp))
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, AndroidAnalyzer.MODULE_NAME, attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME,
file.getName() + "Location History")) abstractFile.getName() + " Location History"))
artifact.addAttributes(attributes) artifact.addAttributes(attributes)
#Not storing these for now. #Not storing these for now.
@ -136,15 +101,13 @@ class CacheLocationAnalyzer(general.AndroidComponentAnalyzer):
try: try:
# index the artifact for keyword search # index the artifact for keyword search
blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard() blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard()
blackboard.postArtifact(artifact, MODULE_NAME) blackboard.postArtifact(artifact, general.MODULE_NAME)
except Blackboard.BlackboardException as ex: except Blackboard.BlackboardException as ex:
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + str(artifact.getArtifactID()), ex) self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + str(artifact.getArtifactID()), ex)
self._logger.log(Level.SEVERE, traceback.format_exc()) self._logger.log(Level.SEVERE, traceback.format_exc())
MessageNotifyUtil.Notify.error("Failed to index GPS trackpoint artifact for keyword search.", artifact.getDisplayName()) MessageNotifyUtil.Notify.error("Failed to index GPS trackpoint artifact for keyword search.", artifact.getDisplayName())
cacheFile.close()
except SQLException as ex:
# Unable to execute Cached GPS locations SQL query against database.
pass
except Exception as ex: except Exception as ex:
self._logger.log(Level.SEVERE, "Error parsing Cached GPS locations to blackboard", ex) self._logger.log(Level.SEVERE, "Error parsing Cached GPS locations to blackboard", ex)
self._logger.log(Level.SEVERE, traceback.format_exc()) self._logger.log(Level.SEVERE, traceback.format_exc())