diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesNodeWorker.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesNodeWorker.java index dcc3375d4d..8f0ed3b13b 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesNodeWorker.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/OtherOccurrencesNodeWorker.java @@ -117,11 +117,14 @@ class OtherOccurrencesNodeWorker extends SwingWorker } int totalCount = 0; Set dataSources = new HashSet<>(); + String currentCaseName = Case.getCurrentCase().getName(); for (CorrelationAttributeInstance corAttr : correlationAttributes) { for (NodeData nodeData : OtherOccurrences.getCorrelatedInstances(deviceId, dataSourceName, corAttr).values()) { try { - dataSources.add(OtherOccurrences.makeDataSourceString(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getDeviceID(), nodeData.getDataSourceName())); - caseNames.put(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getCorrelationAttributeInstance().getCorrelationCase()); + if(!currentCaseName.equals(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID())) { + dataSources.add(OtherOccurrences.makeDataSourceString(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getDeviceID(), nodeData.getDataSourceName())); + caseNames.put(nodeData.getCorrelationAttributeInstance().getCorrelationCase().getCaseUUID(), nodeData.getCorrelationAttributeInstance().getCorrelationCase()); + } } catch (CentralRepoException ex) { logger.log(Level.WARNING, "Unable to get correlation case for displaying other occurrence for case: " + nodeData.getCaseName(), ex); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/annotations/AnnotationUtils.java b/Core/src/org/sleuthkit/autopsy/contentviewers/annotations/AnnotationUtils.java index efa329f843..f17eb3597a 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/annotations/AnnotationUtils.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/annotations/AnnotationUtils.java @@ -219,7 +219,9 @@ public class AnnotationUtils { // if artifact is a hashset hit or interesting file and has a non-blank comment if ((BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() == bba.getArtifactTypeID() - || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == bba.getArtifactTypeID() || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ITEM.getTypeID() == bba.getArtifactTypeID()) + || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == bba.getArtifactTypeID() + || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == bba.getArtifactTypeID() + || BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ITEM.getTypeID() == bba.getArtifactTypeID()) && (hasTskComment(bba))) { boolean filesetRendered = appendEntries(parent, ARTIFACT_COMMENT_CONFIG, Arrays.asList(bba), false, !contentRendered); @@ -339,7 +341,7 @@ public class AnnotationUtils { try { SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); return tskCase.getBlackboardArtifacts(type, sourceFile.getId()).stream() - .filter((bba) -> hasTskComment(bba)) + .filter((bba) -> hasTskComment(bba) || hasTskSet(bba)) .collect(Collectors.toList()); } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS @@ -359,6 +361,17 @@ public class AnnotationUtils { private static boolean hasTskComment(BlackboardArtifact artifact) { return StringUtils.isNotBlank(tryGetAttribute(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT)); } + + /** + * Returns true if the artifact contains a non-blank TSK_SET_NAME attribute. + * + * @param artifact The artifact to check. + * + * @return True if it has a non-blank TSK_SET_NAME. + */ + private static boolean hasTskSet(BlackboardArtifact artifact) { + return StringUtils.isNotBlank(tryGetAttribute(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); + } /** * Attempts to retrieve the attribute of a particular type from a blackboard diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties-MERGED index c529a8aa9d..23afce19fb 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/Bundle.properties-MERGED @@ -8,6 +8,7 @@ CallLogArtifactViewer_label_date=Date CallLogArtifactViewer_label_direction=Direction CallLogArtifactViewer_label_duration=Duration CallLogArtifactViewer_label_from=From +CallLogArtifactViewer_label_hostName=Host CallLogArtifactViewer_label_to=To CallLogArtifactViewer_suffix_local=(Local) CallLogArtifactViewer_value_unknown=Unknown @@ -29,6 +30,7 @@ ContactArtifactViewer_heading_Source=Source # {0} - accountIdentifer ContactArtifactViewer_id_not_found_in_cr=Unable to find account(s) associated with contact {0} in the Central Repository. ContactArtifactViewer_label_datasource=Data Source +ContactArtifactViewer_label_host=Host ContactArtifactViewer_missing_account_label=Missing contact account ContactArtifactViewer_others_header=Other ContactArtifactViewer_persona_account_justification=Account found in Contact artifact @@ -65,6 +67,7 @@ GeneralPurposeArtifactViewer.details.sourceHeader=Source GeneralPurposeArtifactViewer.noFile.text=\ (no longer exists) GeneralPurposeArtifactViewer.term.label=Term GeneralPurposeArtifactViewer.unknown.text=Unknown +GeneralPurposeArtifactViewer_details_host=Host GeneralPurposeArtifactViewer_menuitem_copy=Copy MessageAccountPanel.account.justification=Account found in Message artifact MessageAccountPanel_button_create_label=Create diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java index 0830e8e6ef..096a25040e 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.logging.Level; import javax.swing.JScrollPane; @@ -36,6 +37,8 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.coreutils.Logger; @@ -100,7 +103,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac CallLogViewData callLogViewData = null; try { callLogViewData = getCallLogViewData(artifact); - } catch (TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.SEVERE, String.format("Error getting attributes for Calllog artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex); } List personaSearchDataList = new ArrayList<>(); @@ -115,7 +118,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac } else { currentAccountFetcher = null; } - + // repaint this.revalidate(); this.repaint(); @@ -130,7 +133,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac * * @throws TskCoreException */ - private CallLogViewData getCallLogViewData(BlackboardArtifact artifact) throws TskCoreException { + private CallLogViewData getCallLogViewData(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException { if (artifact == null) { return null; @@ -239,6 +242,12 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac callLogViewData.setFromContactNameList(fromContactNames); callLogViewData.setToContactNameList(toContactNames); + + String hostName = Optional.ofNullable(Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHostByDataSource((DataSource) dataSource)) + .map(h -> h.getName()) + .orElse(null); + + callLogViewData.setHostName(hostName); } return callLogViewData; @@ -413,9 +422,14 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac */ @NbBundle.Messages({ "CallLogArtifactViewer_heading_Source=Source", - "CallLogArtifactViewer_label_datasource=Data Source",}) + "CallLogArtifactViewer_label_datasource=Data Source", + "CallLogArtifactViewer_label_hostName=Host"}) private void updateSourceView(CallLogViewData callLogViewData) { CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, this.m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.CallLogArtifactViewer_heading_Source()); + + CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_hostName()); + CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, StringUtils.defaultString(callLogViewData.getHostName())); + CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_datasource()); CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, callLogViewData.getDataSourceName()); } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogViewData.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogViewData.java index f7888ed7ec..16c42927be 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogViewData.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogViewData.java @@ -32,6 +32,8 @@ final class CallLogViewData { private String fromAccount = null; private String toAccount = null; + + private String hostName = null; // account identifier of the device owner, if known. // will be one of the to or from account. @@ -174,4 +176,11 @@ final class CallLogViewData { return Collections.unmodifiableList(this.fromContactNameList); } + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java index c65b92b8d3..9c05f98114 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java @@ -48,6 +48,7 @@ import org.apache.commons.lang.StringUtils; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; @@ -65,6 +66,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.CommunicationsManager; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.InvalidAccountIDException; import org.sleuthkit.datamodel.TskCoreException; @@ -85,6 +87,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac private BlackboardArtifact contactArtifact; private String contactName; private String datasourceName; + private String hostName; private List phoneNumList = new ArrayList<>(); private List emailList = new ArrayList<>(); @@ -134,7 +137,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac if (artifact != null) { try { extractArtifactData(artifact); - } catch (TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex); return; } @@ -164,7 +167,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac * * @throws TskCoreException */ - private void extractArtifactData(BlackboardArtifact artifact) throws TskCoreException { + private void extractArtifactData(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException { this.contactArtifact = artifact; @@ -193,6 +196,10 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac } datasourceName = contactArtifact.getDataSource().getName(); + + hostName = Optional.ofNullable(Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHostByDataSource((DataSource) contactArtifact.getDataSource())) + .map(h -> h.getName()) + .orElse(null); } /** @@ -248,7 +255,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac int prevGridWidth = contactPanelConstraints.gridwidth; contactPanelConstraints.gridwidth = 3; contactPanelConstraints.anchor = GridBagConstraints.LINE_START; - + javax.swing.JLabel contactImage = new javax.swing.JLabel(); contactImage.setIcon(getImageFromArtifact(contactArtifact)); contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text()); @@ -317,9 +324,12 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac */ @NbBundle.Messages({ "ContactArtifactViewer_heading_Source=Source", - "ContactArtifactViewer_label_datasource=Data Source",}) + "ContactArtifactViewer_label_datasource=Data Source", + "ContactArtifactViewer_label_host=Host",}) private void updateSource() { CommunicationArtifactViewerHelper.addHeader(this, this.m_gridBagLayout, m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_heading_Source()); + CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_host()); + CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, StringUtils.defaultString(hostName)); CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource()); CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, datasourceName); } @@ -350,7 +360,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac this.personaSearchStatusLabel = new javax.swing.JLabel(); personaSearchStatusLabel.setText(personaStatusLabelText); personaSearchStatusLabel.setFont(ContentViewerDefaults.getMessageFont()); - + m_constraints.gridx = 0; m_constraints.anchor = GridBagConstraints.LINE_START; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java index e81b6705c6..273120086a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/GeneralPurposeArtifactViewer.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.contentviewers.artifactviewers; -import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; @@ -30,13 +29,11 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.logging.Level; -import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; @@ -44,9 +41,10 @@ import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; @@ -54,6 +52,7 @@ import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.discovery.ui.AbstractArtifactDetailsPanel; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; /** @@ -146,7 +145,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()}); } - + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @NbBundle.Messages({"GeneralPurposeArtifactViewer.unknown.text=Unknown"}) @Override @@ -154,6 +153,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i resetComponent(); if (artifact != null) { String dataSourceName = Bundle.GeneralPurposeArtifactViewer_unknown_text(); + String hostName = Bundle.GeneralPurposeArtifactViewer_unknown_text(); String sourceFileName = Bundle.GeneralPurposeArtifactViewer_unknown_text(); Map> attributeMap = new HashMap<>(); try { @@ -167,11 +167,16 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i attributeMap.put(bba.getAttributeType().getTypeID(), attrList); } dataSourceName = artifact.getDataSource().getName(); + + hostName = Optional.ofNullable(Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHostByDataSource((DataSource) artifact.getDataSource())) + .map(h -> h.getName()) + .orElse(null); + sourceFileName = artifact.getParent().getUniquePath(); - } catch (TskCoreException ex) { + } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "Unable to get attributes for artifact " + artifact.getArtifactID(), ex); } - updateView(artifact, attributeMap, dataSourceName, sourceFileName); + updateView(artifact, attributeMap, dataSourceName, hostName, sourceFileName); } detailsScrollPane.setViewportView(detailsPanel); detailsScrollPane.revalidate(); @@ -194,7 +199,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i gridBagConstraints.fill = GridBagConstraints.NONE; gridBagConstraints.insets = ZERO_INSETS; } - + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) @Override public boolean isSupported(BlackboardArtifact artifact) { @@ -209,10 +214,11 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i || artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID() || artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL.getTypeID()); } - + @NbBundle.Messages({"GeneralPurposeArtifactViewer.details.attrHeader=Details", "GeneralPurposeArtifactViewer.details.sourceHeader=Source", "GeneralPurposeArtifactViewer.details.dataSource=Data Source", + "GeneralPurposeArtifactViewer_details_host=Host", "GeneralPurposeArtifactViewer.details.file=File", "GeneralPurposeArtifactViewer.details.datesHeader=Dates"}) /** @@ -249,6 +255,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i * @param attributeMap The map of attributes that exist for the artifact. * @param dataSourceName The name of the datasource that caused the creation * of the artifact. + * @param hostName The host name. * @param sourceFilePath The path of the file that caused the creation of * the artifact. */ @@ -260,7 +267,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i "GeneralPurposeArtifactViewer.details.otherHeader=Other", "GeneralPurposeArtifactViewer.noFile.text= (no longer exists)"}) @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - private void updateView(BlackboardArtifact artifact, Map> attributeMap, String dataSourceName, String sourceFilePath) { + private void updateView(BlackboardArtifact artifact, Map> attributeMap, String dataSourceName, String hostName, String sourceFilePath) { final Integer artifactTypeId = artifact.getArtifactTypeID(); if (!(artifactTypeId < 1 || artifactTypeId >= Integer.MAX_VALUE)) { JTextPane firstTextPane = addDetailsHeader(artifactTypeId); @@ -312,6 +319,7 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i } } addHeader(Bundle.GeneralPurposeArtifactViewer_details_sourceHeader()); + addNameValueRow(Bundle.GeneralPurposeArtifactViewer_details_host(), StringUtils.defaultString(hostName)); addNameValueRow(Bundle.GeneralPurposeArtifactViewer_details_dataSource(), dataSourceName); addNameValueRow(Bundle.GeneralPurposeArtifactViewer_details_file(), sourceFilePath); // add veritcal glue at the end @@ -398,10 +406,10 @@ public class GeneralPurposeArtifactViewer extends AbstractArtifactDetailsPanel i headingLabel.setEditable(false); // add a blank line before the start of new section, unless it's // the first section - gridBagConstraints.insets = (gridBagConstraints.gridy == 0) + gridBagConstraints.insets = (gridBagConstraints.gridy == 0) ? FIRST_HEADER_INSETS : HEADER_INSETS; - + gridBagConstraints.gridy++; gridBagConstraints.gridx = LABEL_COLUMN;; // let the header span all of the row diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java index 4a63631d54..d97df57861 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java @@ -181,7 +181,8 @@ public class OsAccountDataPanel extends JPanel { "OsAccountDataPanel_basic_address=Address", "OsAccountDataPanel_basic_admin=Administrator", "OsAccountDataPanel_basic_type=Type", - "OsAccountDataPanel_basic_creationDate=Creation Date",}) + "OsAccountDataPanel_basic_creationDate=Creation Date", + "OsAccountDataPanel_basic_objId=Object ID"}) /** * Returns the data for the Basic Properties section of the panel. @@ -211,6 +212,8 @@ public class OsAccountDataPanel extends JPanel { Optional crTime = account.getCreationTime(); data.addData(Bundle.OsAccountDataPanel_basic_creationDate(), crTime.isPresent() ? TimeZoneUtils.getFormattedTime(crTime.get()) : ""); + + data.addData(Bundle.OsAccountDataPanel_basic_objId(), Long.toString(account.getId())); section.addSectionData(data); return section; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java index 5ded426270..cd4a75fff1 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java @@ -22,6 +22,8 @@ import com.google.common.collect.Lists; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.awt.Image; import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.io.IOException; import java.lang.ref.SoftReference; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -38,6 +40,7 @@ import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; +import javax.imageio.ImageIO; import javax.swing.SwingUtilities; import javax.swing.Timer; import org.apache.commons.lang3.StringUtils; @@ -71,6 +74,9 @@ class ThumbnailViewChildren extends Children.Keys { @NbBundle.Messages("ThumbnailViewChildren.progress.cancelling=(Cancelling)") private static final String CANCELLING_POSTIX = Bundle.ThumbnailViewChildren_progress_cancelling(); + + private static Image waitingIcon; + static final int IMAGES_PER_PAGE = 200; private final ExecutorService executor = Executors.newFixedThreadPool(3, @@ -80,6 +86,23 @@ class ThumbnailViewChildren extends Children.Keys { private final Node parent; private final List> pages = new ArrayList<>(); private int thumbSize; + + + /** + * @return The thumbnail to show while waiting to load the thumbnail. + */ + private static Image getWaitingIcon() { + if (waitingIcon == null) { + String imgPath = "/org/sleuthkit/autopsy/images/working_spinner.gif"; + try { + waitingIcon = ImageIO.read(ThumbnailViewNode.class.getResource(imgPath)); + } catch (IOException ex) { + logger.log(Level.WARNING, "There was an error loading image: " + imgPath, ex); + } + } + + return waitingIcon; + } /** * The constructor @@ -260,8 +283,6 @@ class ThumbnailViewChildren extends Children.Keys { private final Logger logger = Logger.getLogger(ThumbnailViewNode.class.getName()); - private final Image waitingIcon = Toolkit.getDefaultToolkit().createImage(ThumbnailViewNode.class.getResource("/org/sleuthkit/autopsy/images/working_spinner.gif")); //NOI18N - private SoftReference thumbCache = null; private int thumbSize; private final Content content; @@ -309,7 +330,8 @@ class ThumbnailViewChildren extends Children.Keys { waitSpinnerTimer = new Timer(1, actionEvent -> fireIconChange()); waitSpinnerTimer.start(); } - return waitingIcon; + + return getWaitingIcon(); } synchronized void setThumbSize(int iconSize) { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java index 07918f1f88..f113bce296 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/datamodel/PastCasesSummary.java @@ -28,14 +28,13 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; +import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; @@ -70,42 +69,51 @@ public class PastCasesSummary { */ public static class PastCasesResult { - private final List> sameIdsResults; - private final List> taggedNotable; + private final List> previouslyNotable; + private final List> previouslySeenDevices; + private final List> previouslySeenResults; /** * Main constructor. * - * @param sameIdsResults Data for the cases with same id table. - * @param taggedNotable Data for the tagged notable table. + * @param previouslyNotable TSK_PREVIOUSLY_NOTABLE results. + * @param previouslySeenDevices TSK_PREVIOUSLY_SEEN device results. + * @param previouslySeenResults TSK_PREVIOUSLY_SEEN non-device results. */ - public PastCasesResult(List> sameIdsResults, List> taggedNotable) { - this.sameIdsResults = sameIdsResults; - this.taggedNotable = taggedNotable; + public PastCasesResult(List> previouslyNotable, List> previouslySeenDevices, List> previouslySeenResults) { + this.previouslyNotable = Collections.unmodifiableList(previouslyNotable); + this.previouslySeenDevices = Collections.unmodifiableList(previouslySeenDevices); + this.previouslySeenResults = Collections.unmodifiableList(previouslySeenResults); } /** - * @return Data for the cases with same id table. + * @return TSK_PREVIOUSLY_NOTABLE results. */ - public List> getSameIdsResults() { - return Collections.unmodifiableList(sameIdsResults); + public List> getPreviouslyNotable() { + return previouslyNotable; } /** - * @return Data for the tagged notable table. + * @return TSK_PREVIOUSLY_SEEN device results. */ - public List> getTaggedNotable() { - return Collections.unmodifiableList(taggedNotable); + public List> getPreviouslySeenDevices() { + return previouslySeenDevices; + } + + /** + * @return TSK_PREVIOUSLY_SEEN non-device results. + */ + public List> getPreviouslySeenResults() { + return previouslySeenResults; } } private static final Set ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList( - ARTIFACT_TYPE.TSK_PREVIOUSLY_SEEN.getTypeID(), + ARTIFACT_TYPE.TSK_PREVIOUSLY_SEEN.getTypeID(), ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE.getTypeID() )); private static final String CENTRAL_REPO_INGEST_NAME = CentralRepoIngestModuleFactory.getModuleName().toUpperCase().trim(); - private static final BlackboardAttribute.Type TYPE_COMMENT = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_OTHER_CASES); private static final Set CR_DEVICE_TYPE_IDS = new HashSet<>(Arrays.asList( ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID(), @@ -180,11 +188,24 @@ public class PastCasesSummary { BlackboardAttribute commentAttr = null; try { - commentAttr = artifact.getAttribute(TYPE_COMMENT); + commentAttr = artifact.getAttribute(BlackboardAttribute.Type.TSK_OTHER_CASES); } catch (TskCoreException ignored) { // ignore if no attribute can be found } + return getCasesFromAttr(commentAttr); + + } + + /** + * Gets a list of cases from the TSK_OTHER_CASES attribute. The cases string + * is expected to be of a form of "case1,case2...caseN". + * + * @param artifact The attribute. + * + * @return The list of cases if found or empty list if not. + */ + private static List getCasesFromAttr(BlackboardAttribute commentAttr) { if (commentAttr == null) { return Collections.emptyList(); } @@ -197,7 +218,6 @@ public class PastCasesSummary { return Stream.of(justCasesStr.split(CASE_SEPARATOR)) .map(String::trim) .collect(Collectors.toList()); - } /** @@ -228,7 +248,25 @@ public class PastCasesSummary { } /** - * Given a TSK_PREVIOUSLY_SEEN or TSK_PREVIOUSLY_NOTABLE artifact, retrieves it's parent artifact. + * Determines a list of counts for most populated cases based on comment + * attribute. + * + * @param artifacts The list of artifacts. + * + * @return The key value pairs mapping case to counts. + */ + private static List> getCaseCountsFromArtifacts(List artifacts) { + List cases = new ArrayList<>(); + for (BlackboardArtifact art : artifacts) { + cases.addAll(getCasesFromArtifact(art)); + } + + return getCaseCounts(cases.stream()); + } + + /** + * Given a TSK_PREVIOUSLY_SEEN or TSK_PREVIOUSLY_NOTABLE artifact, retrieves + * it's parent artifact. * * @param artifact The input artifact. * @@ -241,7 +279,7 @@ public class PastCasesSummary { BlackboardArtifact sourceArtifact = null; SleuthkitCase skCase = caseProvider.get(); - Content content = skCase.getContentById(artifact.getObjectID()); + Content content = skCase.getContentById(artifact.getObjectID()); if (content instanceof BlackboardArtifact) { sourceArtifact = (BlackboardArtifact) content; } @@ -285,28 +323,31 @@ public class PastCasesSummary { return null; } - SleuthkitCase skCase = caseProvider.get(); + long dataSourceId = dataSource.getId(); - List deviceArtifactCases = new ArrayList<>(); - List nonDeviceArtifactCases = new ArrayList<>(); - for (Integer typeId : ARTIFACT_UPDATE_TYPE_IDS) { - for (BlackboardArtifact artifact : skCase.getBlackboard().getArtifacts(typeId, dataSource.getId())) { - List cases = getCasesFromArtifact(artifact); - if (cases == null || cases.isEmpty()) { - continue; - } + Blackboard blackboard = caseProvider.get().getBlackboard(); - if (hasDeviceAssociatedArtifact(artifact)) { - deviceArtifactCases.addAll(cases); - } else { - nonDeviceArtifactCases.addAll(cases); - } + List previouslyNotableArtifacts + = blackboard.getArtifacts(BlackboardArtifact.Type.TSK_PREVIOUSLY_NOTABLE.getTypeID(), dataSourceId); + + List previouslySeenArtifacts + = blackboard.getArtifacts(BlackboardArtifact.Type.TSK_PREVIOUSLY_SEEN.getTypeID(), dataSourceId); + + List previouslySeenDevice = new ArrayList<>(); + List previouslySeenNoDevice = new ArrayList<>(); + + for (BlackboardArtifact art : previouslySeenArtifacts) { + if (hasDeviceAssociatedArtifact(art)) { + previouslySeenDevice.add(art); + } else { + previouslySeenNoDevice.add(art); } - } - + } + return new PastCasesResult( - getCaseCounts(deviceArtifactCases.stream()), - getCaseCounts(nonDeviceArtifactCases.stream()) + getCaseCountsFromArtifacts(previouslyNotableArtifacts), + getCaseCountsFromArtifacts(previouslySeenDevice), + getCaseCountsFromArtifacts(previouslySeenNoDevice) ); } } diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties index 0833ef9b2d..99ce601968 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties @@ -39,8 +39,6 @@ AnalysisPanel.interestingItemLabel.text=Interesting Item Hits RecentFilesPanel.openDocsLabel.text=Recently Opened Documents RecentFilesPanel.downloadLabel.text=Recent Downloads RecentFilesPanel.attachmentLabel.text=Recent Attachments -PastCasesPanel.notableFileLabel.text=Cases with Common Items That Were Tagged as Notable -PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs DataSourceSummaryTabbedPane.noDataSourceLabel.text=No data source has been selected. TimelinePanel.activityRangeLabel.text=Activity Range GeolocationPanel.withinDistanceLabel.text=Locations further than 150km from a city will be listed as 'Unknown' @@ -62,3 +60,8 @@ ExportPanel.xlsxExportMessage.text=Export Data from Data Source Summary to an Ex ExportPanel.xlsxExportButton.text=Export Summary Data ExcelExportDialog.titleLabel.text=Data Source Summary has been exported to: ExcelExportDialog.okButton.text=OK +PastCasesPanel_notableFileTable_tabName=Cases with Common Items That Were Tagged as Notable +PastCasesPanel.notableFileLabel.text=Cases with common items that were marked as notable +PastCasesPanel.seenDeviceLabel.text=Cases with the same device IDs (USB, Wifi, SIM, etc.) +PastCasesPanel.seenResultLabel.text=Cases with the same addresses (Email, Phone, etc.) +PastCasesPanel.warningLabel.text=NOTE: These results are from the time of ingest. They are not real-time updates. diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED index 06ca641cf7..ebd74379d0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties-MERGED @@ -42,7 +42,7 @@ ContainerPanel.unallocatedSizeValue.text= DataSourceSummaryDialog.window.title=Data Sources Summary DataSourceSummaryNode.column.dataSourceName.header=Data Source Name DataSourceSummaryNode.column.files.header=Files -DataSourceSummaryNode.column.results.header=Results +DataSourceSummaryNode.column.results.header=Artifacts DataSourceSummaryNode.column.status.header=Ingest Status DataSourceSummaryNode.column.tags.header=Tags DataSourceSummaryNode.column.type.header=Type @@ -66,9 +66,7 @@ GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX P GeolocationPanel_unknownRow_title=Unknown PastCasesPanel_caseColumn_title=Case PastCasesPanel_countColumn_title=Count -PastCasesPanel_notableFileTable_tabName=Cases with Common Notable Items at Time Of Ingest PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run. -PastCasesPanel_sameIdsTable_tabName=Past Cases with the Same Devices RecentFilesPanel_attachmentsTable_tabName=Recent Attachments RecentFilesPanel_col_head_date=Date RecentFilesPanel_col_header_domain=Domain @@ -118,8 +116,6 @@ AnalysisPanel.interestingItemLabel.text=Interesting Item Hits RecentFilesPanel.openDocsLabel.text=Recently Opened Documents RecentFilesPanel.downloadLabel.text=Recent Downloads RecentFilesPanel.attachmentLabel.text=Recent Attachments -PastCasesPanel.notableFileLabel.text=Cases with Common Items That Were Tagged as Notable -PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs DataSourceSummaryTabbedPane.noDataSourceLabel.text=No data source has been selected. TimelinePanel.activityRangeLabel.text=Activity Range GeolocationPanel.withinDistanceLabel.text=Locations further than 150km from a city will be listed as 'Unknown' @@ -141,6 +137,11 @@ ExportPanel.xlsxExportMessage.text=Export Data from Data Source Summary to an Ex ExportPanel.xlsxExportButton.text=Export Summary Data ExcelExportDialog.titleLabel.text=Data Source Summary has been exported to: ExcelExportDialog.okButton.text=OK +PastCasesPanel_notableFileTable_tabName=Cases with Common Items That Were Tagged as Notable +PastCasesPanel.notableFileLabel.text=Cases with common items that were marked as notable +PastCasesPanel.seenDeviceLabel.text=Cases with the same device IDs (USB, Wifi, SIM, etc.) +PastCasesPanel.seenResultLabel.text=Cases with the same addresses (Email, Phone, etc.) +PastCasesPanel.warningLabel.text=NOTE: These results are from the time of ingest. They are not real-time updates. UserActivityPanel_noDataExists=No communication data exists UserActivityPanel_tab_title=User Activity UserActivityPanel_TopAccountTableModel_accountType_header=Account Type diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle_ja.properties index ad0869c524..3e93a0ddfc 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/Bundle_ja.properties @@ -121,11 +121,9 @@ IngestJobExcelExport_moduleNameTimeColumn=\u30e2\u30b8\u30e5\u30fc\u30eb\u540d IngestJobExcelExport_sheetName=\u53d6\u8fbc\u307f\u6b74\u53f2 IngestJobExcelExport_startTimeColumn=\u30b9\u30bf\u30fc\u30c8\u6642\u9593 IngestJobExcelExport_versionColumn=\u30e2\u30b8\u30e5\u30fc\u30eb\u30d0\u30fc\u30b8\u30e7\u30f3 -PastCasesPanel.notableFileLabel.text=\u300c\u6ce8\u76ee\u300d\u3068\u30bf\u30b0\u4ed8\u3051\u3055\u308c\u305f\u4e00\u822c\u7684\u306a\u30b1\u30fc\u30b9 -PastCasesPanel.sameIdLabel.text=\u540c\u3058\u30c7\u30d0\u30a4\u30b9ID\u3092\u6301\u3064\u904e\u53bb\u306e\u30b1\u30fc\u30b9 PastCasesPanel_caseColumn_title=\u30b1\u30fc\u30b9 PastCasesPanel_countColumn_title=\u30ab\u30a6\u30f3\u30c8 -PastCasesPanel_notableFileTable_tabName=\u30b1\u30fc\u30b9\u3067\u306e\u5171\u901a\u306a\u6ce8\u76ee\u3059\u3079\u304d\u4e8b\u4f8b +PastCasesPanel_notableFileTable_tabName=\u300c\u6ce8\u76ee\u300d\u3068\u30bf\u30b0\u4ed8\u3051\u3055\u308c\u305f\u4e00\u822c\u7684\u306a\u30b1\u30fc\u30b9 PastCasesPanel_onNoCrIngest_message=\u30bb\u30f3\u30c8\u30e9\u30eb\u30fb\u30ea\u30dd\u30b8\u30c8\u30ea\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u5b9f\u884c\u3055\u308c\u306a\u304b\u3063\u305f\u305f\u3081\u3001\u7d50\u679c\u306f\u8868\u793a\u3055\u308c\u307e\u305b\u3093\u3002 PastCasesPanel_sameIdsTable_tabName=\u540c\u3058\u30c7\u30d0\u30a4\u30b9\u3067\u306e\u904e\u53bb\u306e\u30b1\u30fc\u30b9 RecentFilesPanel.attachmentLabel.text=\u6700\u8fd1\u306e\u6dfb\u4ed8\u30d5\u30a1\u30a4\u30eb @@ -213,3 +211,6 @@ UserActivityPanel_TopWebSearchTableModel_translatedResult_header=\u7ffb\u8a33\u6 UserActivityPanel_noDataExists=\u901a\u4fe1\u30c7\u30fc\u30bf\u304c\u3042\u308a\u307e\u305b\u3093 UserActivityPanel_tab_title=\u30e6\u30fc\u30b6\u30fc\u30a2\u30af\u30c6\u30a3\u30d3\u30c6\u30a3 ViewSummaryInformationAction.name.text=\u6982\u8981\u60c5\u5831\u3092\u8868\u793a +PastCasesPanel.seenDeviceLabel.text=\u540c\u3058\u30c7\u30d0\u30a4\u30b9ID\u3092\u6301\u3064\u904e\u53bb\u306e\u30b1\u30fc\u30b9 +PastCasesPanel.seenResultLabel.text=\u540c\u3058\u30c7\u30d0\u30a4\u30b9ID\u3092\u6301\u3064\u904e\u53bb\u306e\u30b1\u30fc\u30b9 +PastCasesPanel.warningLabel.text=\u540c\u3058\u30c7\u30d0\u30a4\u30b9ID\u3092\u6301\u3064\u904e\u53bb\u306e\u30b1\u30fc\u30b9 diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryNode.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryNode.java index 4aa3cf1be3..d17ef6f000 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/DataSourceSummaryNode.java @@ -148,7 +148,7 @@ final class DataSourceSummaryNode extends AbstractNode { "DataSourceSummaryNode.column.status.header=Ingest Status", "DataSourceSummaryNode.column.type.header=Type", "DataSourceSummaryNode.column.files.header=Files", - "DataSourceSummaryNode.column.results.header=Results", + "DataSourceSummaryNode.column.results.header=Artifacts", "DataSourceSummaryNode.column.tags.header=Tags"}) @Override protected Sheet createSheet() { diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form index 7c84d44660..9ae72f4b83 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.form @@ -21,7 +21,7 @@ - + @@ -147,10 +147,10 @@ - + - + @@ -177,7 +177,7 @@ - + @@ -191,24 +191,111 @@ - + - + - + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java index f4b4d6e956..04ccf08686 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/ui/PastCasesPanel.java @@ -40,9 +40,7 @@ import org.sleuthkit.datamodel.DataSource; @Messages({ "PastCasesPanel_caseColumn_title=Case", "PastCasesPanel_countColumn_title=Count", - "PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run.", - "PastCasesPanel_notableFileTable_tabName=Cases with Common Notable Items at Time Of Ingest", - "PastCasesPanel_sameIdsTable_tabName=Past Cases with the Same Devices",}) + "PastCasesPanel_onNoCrIngest_message=No results will be shown because the Central Repository module was not run.",}) public class PastCasesPanel extends BaseDataSourceSummaryPanel { private static final long serialVersionUID = 1L; @@ -66,12 +64,13 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { = Arrays.asList(CASE_COL, COUNT_COL); private final JTablePanel> notableFileTable = JTablePanel.getJTablePanel(DEFAULT_TEMPLATE); - - private final JTablePanel> sameIdTable = JTablePanel.getJTablePanel(DEFAULT_TEMPLATE); + private final JTablePanel> seenDeviceTable = JTablePanel.getJTablePanel(DEFAULT_TEMPLATE); + private final JTablePanel> seenResultTable = JTablePanel.getJTablePanel(DEFAULT_TEMPLATE); private final List> tables = Arrays.asList( notableFileTable, - sameIdTable + seenResultTable, + seenDeviceTable ); private final List> dataFetchComponents; @@ -109,8 +108,9 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { * @param result The result. */ private void handleResult(DataFetchResult result) { - notableFileTable.showDataFetchResult(DataFetchResult.getSubResult(result, (res) -> res.getTaggedNotable())); - sameIdTable.showDataFetchResult(DataFetchResult.getSubResult(result, (res) -> res.getSameIdsResults())); + notableFileTable.showDataFetchResult(DataFetchResult.getSubResult(result, res -> res.getPreviouslyNotable())); + seenResultTable.showDataFetchResult(DataFetchResult.getSubResult(result, res -> res.getPreviouslySeenResults())); + seenDeviceTable.showDataFetchResult(DataFetchResult.getSubResult(result, res -> res.getPreviouslySeenDevices())); } @Override @@ -145,10 +145,15 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); javax.swing.JPanel notableFilePanel = notableFileTable; javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); - javax.swing.JLabel sameIdLabel = new javax.swing.JLabel(); + javax.swing.JLabel seenResultLabel = new javax.swing.JLabel(); javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); - javax.swing.JPanel sameIdPanel = sameIdTable; - javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); + javax.swing.JPanel seenResultPanel = seenResultTable; + javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); + javax.swing.JLabel seenDeviceLabel = new javax.swing.JLabel(); + javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2)); + javax.swing.JPanel seenDevicePanel = seenDeviceTable; + javax.swing.Box.Filler filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20)); + javax.swing.JLabel warningLabel = new javax.swing.JLabel(); mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10)); mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS)); @@ -175,21 +180,39 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { filler2.setAlignmentX(0.0F); mainContentPanel.add(filler2); - org.openide.awt.Mnemonics.setLocalizedText(sameIdLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.sameIdLabel.text")); // NOI18N - mainContentPanel.add(sameIdLabel); + org.openide.awt.Mnemonics.setLocalizedText(seenResultLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.seenResultLabel.text")); // NOI18N + mainContentPanel.add(seenResultLabel); filler3.setAlignmentX(0.0F); mainContentPanel.add(filler3); - sameIdPanel.setAlignmentX(0.0F); - sameIdPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); - sameIdPanel.setMinimumSize(new java.awt.Dimension(100, 106)); - sameIdPanel.setPreferredSize(new java.awt.Dimension(100, 106)); - mainContentPanel.add(sameIdPanel); + seenResultPanel.setAlignmentX(0.0F); + seenResultPanel.setMaximumSize(new java.awt.Dimension(32767, 106)); + seenResultPanel.setMinimumSize(new java.awt.Dimension(100, 106)); + seenResultPanel.setPreferredSize(new java.awt.Dimension(100, 106)); + mainContentPanel.add(seenResultPanel); + + filler4.setAlignmentX(0.0F); + mainContentPanel.add(filler4); + + org.openide.awt.Mnemonics.setLocalizedText(seenDeviceLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.seenDeviceLabel.text")); // NOI18N + mainContentPanel.add(seenDeviceLabel); filler5.setAlignmentX(0.0F); mainContentPanel.add(filler5); + seenDevicePanel.setAlignmentX(0.0F); + seenDevicePanel.setMaximumSize(new java.awt.Dimension(32767, 106)); + seenDevicePanel.setMinimumSize(new java.awt.Dimension(100, 106)); + seenDevicePanel.setPreferredSize(new java.awt.Dimension(100, 106)); + mainContentPanel.add(seenDevicePanel); + + filler6.setAlignmentX(0.0F); + mainContentPanel.add(filler6); + + org.openide.awt.Mnemonics.setLocalizedText(warningLabel, org.openide.util.NbBundle.getMessage(PastCasesPanel.class, "PastCasesPanel.warningLabel.text")); // NOI18N + mainContentPanel.add(warningLabel); + mainScrollPane.setViewportView(mainContentPanel); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); @@ -200,7 +223,7 @@ public class PastCasesPanel extends BaseDataSourceSummaryPanel { ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE) + .addComponent(mainScrollPane) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/SwingWorkerSequentialExecutor.java b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/SwingWorkerSequentialExecutor.java index 37c46df31c..b0a4ea679f 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/SwingWorkerSequentialExecutor.java +++ b/Core/src/org/sleuthkit/autopsy/datasourcesummary/uiutils/SwingWorkerSequentialExecutor.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.datasourcesummary.uiutils; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -36,7 +37,7 @@ import javax.swing.SwingWorker; */ public class SwingWorkerSequentialExecutor { - private final ExecutorService executorService = Executors.newFixedThreadPool(1); + private final ExecutorService executorService = Executors.newFixedThreadPool(1, new ThreadFactoryBuilder().setNameFormat("SwingWorkerSequentialExecutor-%d").build()); private List> workers = Collections.emptyList(); private List> futures = Collections.emptyList(); diff --git a/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java index 3e44c4718a..9a07b9fd7c 100644 --- a/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java +++ b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java @@ -30,6 +30,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.logging.Level; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.NbBundle.Messages; @@ -143,6 +144,7 @@ class ImageWriter implements PropertyChangeListener { }) private void startFinishImage(String dataSourceName) { + ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("ImageWriter-startFinishImage-%d").build()); synchronized (currentTasksLock) { if (isCancelled) { return; @@ -186,7 +188,7 @@ class ImageWriter implements PropertyChangeListener { // The added complexity here with the Future is because we absolutely need to make sure // the call to finishImageWriter returns before allowing the TSK data structures to be freed // during case close. - finishTask = Executors.newSingleThreadExecutor().submit(new Callable() { + finishTask = executor.submit(new Callable() { @Override public Integer call() throws TskCoreException { try { @@ -199,7 +201,7 @@ class ImageWriter implements PropertyChangeListener { caseDb.updateImagePath(settings.getPath(), dataSourceId); } return result; - } catch (TskCoreException ex) { + } catch (Throwable ex) { logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS return -1; } @@ -215,6 +217,7 @@ class ImageWriter implements PropertyChangeListener { try { // The call to get() can happen multiple times if the user closes the case, which is ok result = finishTask.get(); + executor.shutdownNow(); } catch (InterruptedException | ExecutionException ex) { logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 1f3d3ee4fd..bb958b14f6 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -644,7 +644,6 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { if (factory.isDataSourceIngestModuleFactory()) { String uniqueName = FactoryClassNameNormalizer.normalize(factory.getClass().getCanonicalName()) + "-" + factory.getModuleDisplayName() + "-" - + IngestModuleInfo.IngestModuleType.DATA_SOURCE_LEVEL.toString() + "-" + factory.getModuleVersionNumber(); for (IngestModuleInfo ingestModuleInfo : ingestJob.getIngestModuleInfo()) { boolean sameModule = ingestModuleInfo.getUniqueName().equals(uniqueName); @@ -659,7 +658,6 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { if (factory.isFileIngestModuleFactory()) { String uniqueName = FactoryClassNameNormalizer.normalize(factory.getClass().getCanonicalName()) + "-" + factory.getModuleDisplayName() + "-" - + IngestModuleInfo.IngestModuleType.FILE_LEVEL.toString() + "-" + factory.getModuleVersionNumber(); for (IngestModuleInfo ingestModuleInfo : ingestJob.getIngestModuleInfo()) { boolean sameModule = ingestModuleInfo.getUniqueName().equals(uniqueName); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index d868b39189..364f337a78 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -30,7 +30,6 @@ import javax.swing.WindowConstants; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.Executors; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; @@ -291,16 +290,13 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P if (referenceSetID.get() >= 0) { // This can be slow on large reference sets - Executors.newSingleThreadExecutor().execute(new Runnable() { - @Override - public void run() { - try { - CentralRepository.getInstance().deleteReferenceSet(referenceSetID.get()); - } catch (CentralRepoException ex2) { - Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Error deleting incomplete hash set from central repository", ex2); - } + new Thread(() -> { + try { + CentralRepository.getInstance().deleteReferenceSet(referenceSetID.get()); + } catch (CentralRepoException ex2) { + Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Error deleting incomplete hash set from central repository", ex2); } - }); + }).start(); } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED index 58f4dcb10e..03d1661133 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/Bundle.properties-MERGED @@ -54,8 +54,9 @@ ExportIngestHistory_startTimeColumn=Start Time ExportIngestHistory_versionColumn=Module Version ExportPastCases_caseColumn_title=Case ExportPastCases_countColumn_title=Count -ExportPastCases_notableFileTable_tabName=Cases with Common Notable Items at Time Of Ingest -ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices +ExportPastCases_notableFileTable_tabName=Cases with common notable items +ExportPastCases_seenDevicesTable_tabName=Cases with the same device IDs +ExportPastCases_seenResultsTable_tabName=Cases with the same addresses ExportRecentFiles_attachmentsTable_tabName=Recent Attachments ExportRecentFiles_col_head_date=Date ExportRecentFiles_col_header_domain=Domain diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java index 96aefebaff..6e97be600d 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/datasourcesummaryexport/ExportPastCases.java @@ -37,10 +37,11 @@ import org.sleuthkit.datamodel.DataSource; @Messages({ "ExportPastCases_caseColumn_title=Case", "ExportPastCases_countColumn_title=Count", - "ExportPastCases_notableFileTable_tabName=Cases with Common Notable Items at Time Of Ingest", - "ExportPastCases_sameIdsTable_tabName=Past Cases with the Same Devices",}) + "ExportPastCases_notableFileTable_tabName=Cases with common notable items", + "ExportPastCases_seenResultsTable_tabName=Cases with the same addresses", + "ExportPastCases_seenDevicesTable_tabName=Cases with the same device IDs",}) class ExportPastCases { - + private final PastCasesSummary pastSummary; // model for column indicating the case @@ -73,8 +74,9 @@ class ExportPastCases { } return Arrays.asList( - getTableExport(DEFAULT_TEMPLATE, Bundle.ExportPastCases_notableFileTable_tabName(), result.getTaggedNotable()), - getTableExport(DEFAULT_TEMPLATE, Bundle.ExportPastCases_sameIdsTable_tabName(), result.getSameIdsResults()) + getTableExport(DEFAULT_TEMPLATE, Bundle.ExportPastCases_notableFileTable_tabName(), result.getPreviouslyNotable()), + getTableExport(DEFAULT_TEMPLATE, Bundle.ExportPastCases_seenResultsTable_tabName(), result.getPreviouslySeenResults()), + getTableExport(DEFAULT_TEMPLATE, Bundle.ExportPastCases_seenDevicesTable_tabName(), result.getPreviouslySeenDevices()) ); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java index 6f0b1d1c2a..e2fde8d03a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.Objects; import static java.util.Objects.nonNull; import java.util.Optional; @@ -55,7 +56,7 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView /** The use of SingleThreadExecutor means we can only load a single image at * a time */ - static final Executor exec = Executors.newSingleThreadExecutor(); + static final Executor exec = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("DrawableUIBase-%d").build()); @FXML BorderPane imageBorder; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java index 234e834149..ee82989908 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.navpanel; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -39,7 +40,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; */ class GroupTreeItem extends TreeItem { - static final Executor treeInsertTread = Executors.newSingleThreadExecutor(); + static final Executor treeInsertTread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("GroupTreeItem-%d").build()); GroupTreeItem getTreeItemForGroup(DrawableGroup grouping) { if (Objects.equals(getValue().getGroup(), grouping)) { diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java index c3ff5017fe..163feec22d 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java @@ -449,9 +449,12 @@ class Firefox extends Extract { NbBundle.getMessage(this.getClass(), "Firefox.moduleName"))); if (checkColumn == true) { - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, - RecentActivityExtracterModuleFactory.getModuleName(), - (Long.valueOf(result.get("creationTime").toString())))); //NON-NLS + String value = result.get("creationTime").toString(); + if(value != null && !value.isEmpty()) { + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, + RecentActivityExtracterModuleFactory.getModuleName(), + (Long.valueOf(result.get("creationTime").toString())))); //NON-NLS + } } String domain = extractDomain(host); if (domain != null && domain.isEmpty() == false) { diff --git a/docs/doxygen/images/projectProperties.png b/docs/doxygen/images/projectProperties.png new file mode 100644 index 0000000000..7a438ac834 Binary files /dev/null and b/docs/doxygen/images/projectProperties.png differ diff --git a/docs/doxygen/modDev.dox b/docs/doxygen/modDev.dox index 53eb6bc416..d220d94623 100644 --- a/docs/doxygen/modDev.dox +++ b/docs/doxygen/modDev.dox @@ -53,11 +53,13 @@ To make a NetBeans module: After the module is created, you will need to do some further configuration.
  • Right click on the newly created module and choose "Properties". +
  • Verify that the Netbeans Platform is set to the Autopsy Platform.
  • You will need to configure the module to be dependent on modules from within the Autopsy platform. Go to the "Libraries" area and choose "Add" in the "Module Dependencies" section. Choose the:
    • "Autopsy-Core" library to get access to the Autopsy services.
    • NetBeans "Lookup API" library so that your module can be discovered by Autopsy.
    +\image html projectProperties.png
  • If you later determine that you need to pull in external JAR files, then you will use the "Wrapped Jar" section to add them in.
  • Note, you will also need to come back to this section if you update the platform. You may need to add a new dependency for the version of the Autopsy-Core that comes with the updated platform.
  • Autopsy requires that all modules restart Autopsy after they are installed. Configure your module this way under Build -> Packaging. Check the box that says Needs Restart on Install.