From a45de89e374f59748ecc90964d5f48018eab398c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 20 Apr 2020 09:56:32 -0400 Subject: [PATCH 01/13] refactoring of PinnedAccountModel --- .../communications/AbstractCVTAction.java | 5 +- .../autopsy/communications/CVTEvents.java | 21 +++---- .../communications/CommunicationsGraph.java | 56 ++++++++++--------- .../communications/PinnedAccountModel.java | 11 ++-- .../autopsy/communications/StateManager.java | 14 +++-- .../communications/VisualizationPanel.java | 2 +- 6 files changed, 60 insertions(+), 49 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java index ef751d262c..a02f0c0e86 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java @@ -24,6 +24,7 @@ import javax.swing.ImageIcon; import javax.swing.JMenuItem; import org.openide.util.Utilities; import org.openide.util.actions.Presenter; +import org.sleuthkit.datamodel.AccountDeviceInstance; /** * Base class for actions that act on the selected AccountDeviceInstanceKeys. @@ -37,8 +38,8 @@ abstract class AbstractCVTAction extends AbstractAction implements Presenter.Pop * * @return The selected accounts */ - Collection getSelectedAccounts() { - return Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class); + Collection getSelectedAccounts() { + return Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstance.class); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java index ee7224b673..ae3735e30f 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CVTEvents.java @@ -24,6 +24,7 @@ import java.util.Collection; import org.sleuthkit.autopsy.communications.FiltersPanel.DateControlState; import org.sleuthkit.datamodel.CommunicationsFilter; import org.sleuthkit.autopsy.communications.StateManager.CommunicationsState; +import org.sleuthkit.datamodel.AccountDeviceInstance; /** * Provide the singleton EventBus. @@ -73,19 +74,19 @@ final class CVTEvents { */ static final class PinAccountsEvent { - private final ImmutableSet accountDeviceInstances; + private final ImmutableSet accounInstances; private final boolean replace; public boolean isReplace() { return replace; } - ImmutableSet getAccountDeviceInstances() { - return accountDeviceInstances; + ImmutableSet getAccountDeviceInstances() { + return accounInstances; } - PinAccountsEvent(Collection accountDeviceInstances, boolean replace) { - this.accountDeviceInstances = ImmutableSet.copyOf(accountDeviceInstances); + PinAccountsEvent(Collection accountDeviceInstances, boolean replace) { + this.accounInstances = ImmutableSet.copyOf(accountDeviceInstances); this.replace = replace; } } @@ -95,14 +96,14 @@ final class CVTEvents { */ static final class UnpinAccountsEvent { - private final ImmutableSet accountDeviceInstances; + private final ImmutableSet accountInstances; - public ImmutableSet getAccountDeviceInstances() { - return accountDeviceInstances; + public ImmutableSet getAccountDeviceInstances() { + return accountInstances; } - UnpinAccountsEvent(Collection accountDeviceInstances) { - this.accountDeviceInstances = ImmutableSet.copyOf(accountDeviceInstances); + UnpinAccountsEvent(Collection accountDeviceInstances) { + this.accountInstances = ImmutableSet.copyOf(accountDeviceInstances); } } diff --git a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java index 716d00656c..f88edeedcf 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java @@ -32,6 +32,7 @@ import java.io.InputStreamReader; import java.io.StringWriter; import java.net.URL; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -147,7 +148,7 @@ final class CommunicationsGraph extends mxGraph { scopes.put("accountName", adiKey.getAccountDeviceInstance().getAccount().getTypeSpecificID()); scopes.put("size", Math.round(Math.log(adiKey.getMessageCount()) + 5)); scopes.put("iconFileName", CommunicationsGraph.class.getResource(Utils.getIconFilePath(adiKey.getAccountDeviceInstance().getAccount().getAccountType()))); - scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey)); + scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey.getAccountDeviceInstance())); scopes.put("MARKER_PIN_URL", MARKER_PIN_URL); scopes.put("locked", lockedVertexModel.isVertexLocked((mxCell) cell)); scopes.put("LOCK_URL", LOCK_URL); @@ -172,7 +173,7 @@ final class CommunicationsGraph extends mxGraph { scopes.put("accountName", adiKey.getAccountDeviceInstance().getAccount().getTypeSpecificID()); scopes.put("relationships", 12);// Math.round(Math.log(adiKey.getMessageCount()) + 5)); scopes.put("iconFileName", CommunicationsGraph.class.getResource(Utils.getIconFilePath(adiKey.getAccountDeviceInstance().getAccount().getAccountType()))); - scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey)); + scopes.put("pinned", pinnedAccountModel.isAccountPinned(adiKey.getAccountDeviceInstance())); scopes.put("MARKER_PIN_URL", MARKER_PIN_URL); scopes.put("locked", lockedVertexModel.isVertexLocked((mxCell) cell)); scopes.put("LOCK_URL", LOCK_URL); @@ -199,16 +200,23 @@ final class CommunicationsGraph extends mxGraph { lockedVertexModel.clear(); } - private mxCell getOrCreateVertex(AccountDeviceInstanceKey accountDeviceInstanceKey) { - final AccountDeviceInstance accountDeviceInstance = accountDeviceInstanceKey.getAccountDeviceInstance(); + private mxCell getOrCreateVertex(AccountDeviceInstance adi, CommunicationsManager commsManager, CommunicationsFilter currentFilter) { + final AccountDeviceInstance accountDeviceInstance = adi; final String name = accountDeviceInstance.getAccount().getTypeSpecificID(); final mxCell vertex = nodeMap.computeIfAbsent(name + accountDeviceInstance.getDeviceId(), vertexName -> { - double size = Math.sqrt(accountDeviceInstanceKey.getMessageCount()) + 10; + long adiRelationshipsCount = 1; + try { + adiRelationshipsCount = commsManager.getRelationshipSourcesCount(accountDeviceInstance, currentFilter); + } catch (TskCoreException tskCoreException) { + logger.log(Level.SEVERE, "Error", tskCoreException); + } + + double size = Math.sqrt(adiRelationshipsCount) + 10; mxCell newVertex = (mxCell) insertVertex( getDefaultParent(), - name, accountDeviceInstanceKey, + name, adi, Math.random() * 400, Math.random() * 400, size, @@ -219,9 +227,11 @@ final class CommunicationsGraph extends mxGraph { } @SuppressWarnings("unchecked") - private mxCell addOrUpdateEdge(long relSources, AccountDeviceInstanceKey account1, AccountDeviceInstanceKey account2) { - mxCell vertex1 = getOrCreateVertex(account1); - mxCell vertex2 = getOrCreateVertex(account2); + private mxCell addOrUpdateEdge(long relSources, + AccountDeviceInstance account1, AccountDeviceInstance account2, + CommunicationsManager commsManager, CommunicationsFilter currentFilter) { + mxCell vertex1 = getOrCreateVertex(account1, commsManager, currentFilter); + mxCell vertex2 = getOrCreateVertex(account2, commsManager, currentFilter); Object[] edgesBetween = getEdgesBetween(vertex1, vertex2); mxCell edge; if (edgesBetween.length == 0) { @@ -260,28 +270,24 @@ final class CommunicationsGraph extends mxGraph { /** * set to keep track of accounts related to pinned accounts */ - final Map relatedAccounts = new HashMap<>(); - for (final AccountDeviceInstanceKey adiKey : pinnedAccountModel.getPinnedAccounts()) { + final Set relatedAccounts = new HashSet<>(); + for (final AccountDeviceInstance adi : pinnedAccountModel.getPinnedAccounts()) { if (isCancelled()) { break; } //get accounts related to pinned account final List relatedAccountDeviceInstances - = commsManager.getRelatedAccountDeviceInstances(adiKey.getAccountDeviceInstance(), currentFilter); - relatedAccounts.put(adiKey.getAccountDeviceInstance(), adiKey); - getOrCreateVertex(adiKey); + = commsManager.getRelatedAccountDeviceInstances(adi, currentFilter); + relatedAccounts.add(adi); + getOrCreateVertex(adi, commsManager, currentFilter); + + for (final AccountDeviceInstance relatedADI : relatedAccountDeviceInstances) + relatedAccounts.add(relatedADI); - for (final AccountDeviceInstance relatedADI : relatedAccountDeviceInstances) { - final long adiRelationshipsCount = commsManager.getRelationshipSourcesCount(relatedADI, currentFilter); - final AccountDeviceInstanceKey relatedADIKey = new AccountDeviceInstanceKey(relatedADI, currentFilter, adiRelationshipsCount); - relatedAccounts.put(relatedADI, relatedADIKey); //store related accounts - } progressIndicator.progress(++progressCounter); } - Set accounts = relatedAccounts.keySet(); - - Map relationshipCounts = commsManager.getRelationshipCountsPairwise(accounts, currentFilter); + Map relationshipCounts = commsManager.getRelationshipCountsPairwise(relatedAccounts, currentFilter); int total = relationshipCounts.size(); int progress = 0; @@ -290,12 +296,12 @@ final class CommunicationsGraph extends mxGraph { for (Map.Entry entry : relationshipCounts.entrySet()) { Long count = entry.getValue(); AccountPair relationshipKey = entry.getKey(); - AccountDeviceInstanceKey account1 = relatedAccounts.get(relationshipKey.getFirst()); - AccountDeviceInstanceKey account2 = relatedAccounts.get(relationshipKey.getSecond()); + AccountDeviceInstance account1 = relationshipKey.getFirst(); + AccountDeviceInstance account2 = relationshipKey.getSecond(); if (pinnedAccountModel.isAccountPinned(account1) || pinnedAccountModel.isAccountPinned(account2)) { - mxCell addEdge = addOrUpdateEdge(count, account1, account2); + mxCell addEdge = addOrUpdateEdge(count, account1, account2, commsManager, currentFilter); progressText = addEdge.getId(); } progressIndicator.progress(progressText, progress++); diff --git a/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java index c9fe899c3f..9221a487cb 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/PinnedAccountModel.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; import java.util.HashSet; import java.util.Set; +import org.sleuthkit.datamodel.AccountDeviceInstance; /** * Model of what accounts are pinned to a visualization. @@ -34,7 +35,7 @@ class PinnedAccountModel { * to pinned accounts and pass the filters are show. Pinning accounts is the * primary way to populate the graph. */ - private final Set pinnedAccountDevices = new HashSet<>(); + private final Set pinnedAccountDevices = new HashSet<>(); private final EventBus eventBus = new EventBus(); @@ -46,7 +47,7 @@ class PinnedAccountModel { eventBus.unregister(handler); } - boolean isAccountPinned(AccountDeviceInstanceKey account) { + boolean isAccountPinned(AccountDeviceInstance account) { return pinnedAccountDevices.contains(account); } @@ -57,7 +58,7 @@ class PinnedAccountModel { * * @param accountDeviceInstances The accounts to unpin. */ - void unpinAccount(Set accountDeviceInstances) { + void unpinAccount(Set accountDeviceInstances) { pinnedAccountDevices.removeAll(accountDeviceInstances); } @@ -68,7 +69,7 @@ class PinnedAccountModel { * * @param accountDeviceInstances The accounts to pin. */ - void pinAccount(Set accountDeviceInstances) { + void pinAccount(Set accountDeviceInstances) { pinnedAccountDevices.addAll(accountDeviceInstances); } @@ -86,7 +87,7 @@ class PinnedAccountModel { pinnedAccountDevices.clear(); } - ImmutableSet getPinnedAccounts() { + ImmutableSet getPinnedAccounts() { return ImmutableSet.copyOf(pinnedAccountDevices); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/StateManager.java b/Core/src/org/sleuthkit/autopsy/communications/StateManager.java index c84a5beb79..ca1d902153 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/StateManager.java +++ b/Core/src/org/sleuthkit/autopsy/communications/StateManager.java @@ -23,6 +23,8 @@ import java.util.HashSet; import java.util.Set; import org.sleuthkit.autopsy.communications.FiltersPanel.DateControlState; import org.sleuthkit.autopsy.coreutils.History; +import org.sleuthkit.datamodel.Account; +import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.CommunicationsFilter; /** @@ -51,11 +53,11 @@ final class StateManager { @Subscribe void pinAccount(CVTEvents.PinAccountsEvent pinEvent) { if(pinEvent.isReplace()){ - HashSet pinnedList = new HashSet<>(); + HashSet pinnedList = new HashSet<>(); pinnedList.addAll(pinEvent.getAccountDeviceInstances()); historyManager.advance(new CommunicationsState(comFilter, pinnedList, -1, currentStartState, currentEndState)); } else { - HashSet pinnedList = new HashSet<>(); + HashSet pinnedList = new HashSet<>(); pinnedList.addAll(pinEvent.getAccountDeviceInstances()); pinnedList.addAll(pinModel.getPinnedAccounts()); @@ -74,7 +76,7 @@ final class StateManager { @Subscribe void unpinAccounts(CVTEvents.UnpinAccountsEvent pinEvent) { - HashSet pinnedList = new HashSet<>(); + HashSet pinnedList = new HashSet<>(); pinnedList.addAll(pinModel.getPinnedAccounts()); pinnedList.removeAll(pinEvent.getAccountDeviceInstances()); @@ -135,7 +137,7 @@ final class StateManager { */ final class CommunicationsState{ private final CommunicationsFilter communcationFilter; - private final Set pinnedList; + private final Set pinnedList; private final double zoomValue; private final DateControlState startDateState; private final DateControlState endDateState; @@ -149,7 +151,7 @@ final class StateManager { * @param zoomValue Double value of the current graph scale */ protected CommunicationsState(CommunicationsFilter communcationFilter, - Set pinnedList, double zoomValue, + Set pinnedList, double zoomValue, DateControlState startDateState, DateControlState endDateState){ this.pinnedList = pinnedList; this.communcationFilter = communcationFilter; @@ -172,7 +174,7 @@ final class StateManager { * * @return Set of AccountDeviceInstanceKey */ - public Set getPinnedList(){ + public Set getPinnedList(){ return pinnedList; } diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index 1799ebcb8d..51005878ec 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -1100,7 +1100,7 @@ final public class VisualizationPanel extends JPanel { } else { jPopupMenu.add(new JMenuItem(new LockAction(selectedVertices))); } - if (pinnedAccountModel.isAccountPinned(adiKey)) { + if (pinnedAccountModel.isAccountPinned(adiKey.getAccountDeviceInstance())) { jPopupMenu.add(UnpinAccountsAction.getInstance().getPopupPresenter()); } else { jPopupMenu.add(PinAccountsAction.getInstance().getPopupPresenter()); From 1f3acd3647928983aa48bfb50d042746dd74f380 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 20 Apr 2020 10:22:49 -0400 Subject: [PATCH 02/13] some bug fixes --- .../sleuthkit/autopsy/communications/AbstractCVTAction.java | 6 +++++- .../autopsy/communications/CommunicationsGraph.java | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java index a02f0c0e86..95c2d43bbb 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java +++ b/Core/src/org/sleuthkit/autopsy/communications/AbstractCVTAction.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.communications; import java.util.Collection; +import java.util.stream.Collectors; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import javax.swing.JMenuItem; @@ -39,7 +40,10 @@ abstract class AbstractCVTAction extends AbstractAction implements Presenter.Pop * @return The selected accounts */ Collection getSelectedAccounts() { - return Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstance.class); + return Utilities.actionsGlobalContext().lookupAll(AccountDeviceInstanceKey.class) + .stream() + .map((adiKey -> adiKey.getAccountDeviceInstance())) + .collect(Collectors.toSet()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java index f88edeedcf..38a20d07e5 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java @@ -213,10 +213,11 @@ final class CommunicationsGraph extends mxGraph { } double size = Math.sqrt(adiRelationshipsCount) + 10; - + AccountDeviceInstanceKey adiKey = new AccountDeviceInstanceKey(adi, currentFilter, adiRelationshipsCount); + mxCell newVertex = (mxCell) insertVertex( getDefaultParent(), - name, adi, + name, adiKey, Math.random() * 400, Math.random() * 400, size, From 09f46d2b1c5638fea1235f53efd01652cbe76c5f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 20 Apr 2020 11:01:01 -0400 Subject: [PATCH 03/13] remove unused import --- Core/src/org/sleuthkit/autopsy/communications/StateManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/StateManager.java b/Core/src/org/sleuthkit/autopsy/communications/StateManager.java index ca1d902153..3f24a98764 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/StateManager.java +++ b/Core/src/org/sleuthkit/autopsy/communications/StateManager.java @@ -23,7 +23,6 @@ import java.util.HashSet; import java.util.Set; import org.sleuthkit.autopsy.communications.FiltersPanel.DateControlState; import org.sleuthkit.autopsy.coreutils.History; -import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.AccountDeviceInstance; import org.sleuthkit.datamodel.CommunicationsFilter; From 47ac6d5a104255731c0c5287c2784365d633db8c Mon Sep 17 00:00:00 2001 From: Ethan Roseman Date: Mon, 20 Apr 2020 17:06:18 -0400 Subject: [PATCH 04/13] 6267 Preventing datasources with no geodata from appearing in the geolocation panel, also fixing artifact type counts --- .../autopsy/geolocation/GeoFilterPanel.java | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index f9d8fca38e..c78c822af0 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -23,6 +23,8 @@ import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -35,12 +37,13 @@ import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.SpinnerNumberModel; import javax.swing.SwingWorker; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.utils.IconsUtil; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -482,6 +485,50 @@ class GeoFilterPanel extends javax.swing.JPanel { return new Sources(validSources, atCountsTotal); } + /** + * Get a count of TSK_METADATA_EXIF artifacts containing GPS data for + * the given data case and source. Does not include rejected artifacts. + * + * @param sleuthkitCase + * @param dataSourceID + * + * @return The artifacts count that match the criteria + * + * @throws TskCoreException + */ + public long getExifGPSDataCount(SleuthkitCase sleuthkitCase, DataSource dataSource) throws TskCoreException { + long count = 0; + String queryStr + = "SELECT count(*) AS count FROM" + + " (" + + " SELECT artifact_obj_id, group_concat(attribute_type_id) FROM" + + " (" + + " SELECT * FROM blackboard_artifacts as arts" + + " INNER JOIN blackboard_attributes as attrs" + + " ON attrs.artifact_id = arts.artifact_id" + + " WHERE arts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() + + " AND arts.data_source_obj_id = " + dataSource.getId() + + " AND arts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() + + " AND" + + " (" + + "attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID() + + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID() + + " )" + + " )" + + "GROUP BY artifact_obj_id" + + " )"; + try (SleuthkitCase.CaseDbQuery queryResult = sleuthkitCase.executeQuery(queryStr)) { + ResultSet resultSet = queryResult.getResultSet(); + try { + resultSet.next(); + count = resultSet.getLong("count"); + } catch (SQLException ex) { + Exceptions.printStackTrace(ex); + } + } + return count; + } + /** * Returns a Map representing the number of sources found for each * artifact type. If no data was found, an empty map is returned. @@ -496,7 +543,12 @@ class GeoFilterPanel extends javax.swing.JPanel { private Map getGPSDataSources(SleuthkitCase sleuthkitCase, DataSource dataSource) throws TskCoreException { HashMap ret = new HashMap<>(); for (BlackboardArtifact.ARTIFACT_TYPE type : GPS_ARTIFACT_TYPES) { - long count = sleuthkitCase.getBlackboardArtifactsTypeCount(type.getTypeID(), dataSource.getId()); + long count; + if (type == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF) { + count = getExifGPSDataCount(sleuthkitCase, dataSource); + } else { + count = sleuthkitCase.getBlackboardArtifactsTypeCount(type.getTypeID(), dataSource.getId()); + } if (count > 0) { ret.put(type, count); } From c06db98b0fc398c48f928b91e5bc5c8092af16bf Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 21 Apr 2020 15:58:30 -0400 Subject: [PATCH 05/13] Removed reference to brew since the formula is out of date and does not work. --- Running_Linux_OSX.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Running_Linux_OSX.txt b/Running_Linux_OSX.txt index 60b81bc50a..0427c003b4 100644 --- a/Running_Linux_OSX.txt +++ b/Running_Linux_OSX.txt @@ -42,11 +42,10 @@ The following need to be done at least once. They do not need to be repeated for Autopsy depends on a specific version of The Sleuth Kit. You need the Java libraries of The Sleuth Kit installed, which is not part of all packages. -- Linux: Install the sleuthkit-java.deb file that you can download from github.com/sleuthkit/sleuthkit/releases. This will install libewf, etc. --- % sudo apt install ./sleuthkit-java_4.7.0-1_amd64.deb +- Linux: Install the sleuthkit-java.deb file that you can download from github.com/sleuthkit/sleuthkit/releases. This will install libewf, etc. For example: +-- % sudo apt install ./sleuthkit-java_4.8.0-1_amd64.deb -- OS X: Install The Sleuth Kit from brew. --- % brew install sleuthkit +- OS X: Build The Sleuth Kit from source. See https://github.com/sleuthkit/sleuthkit/blob/develop/INSTALL.txt for details. * Install Autopsy * From 4317a3ae27351feb74bcb0a23b6bd9862afaf316 Mon Sep 17 00:00:00 2001 From: Ethan Roseman Date: Tue, 21 Apr 2020 22:50:51 -0400 Subject: [PATCH 06/13] 6285 Better selection range for dots on geo map --- .../autopsy/geolocation/MapPanel.java | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java index 44de21ff81..eea578b0c0 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java @@ -39,6 +39,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -83,9 +84,13 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; final public class MapPanel extends javax.swing.JPanel { static final String CURRENT_MOUSE_GEOPOSITION = "CURRENT_MOUSE_GEOPOSITION"; + private static final Logger logger = Logger.getLogger(MapPanel.class.getName()); private static final long serialVersionUID = 1L; + private static final HashSet DOT_WAYPOINT_TYPES = new HashSet<>(); + private static final int DOT_SIZE = 12; + private boolean zoomChanging; private KdTree waypointTree; private Set waypointSet; @@ -104,6 +109,12 @@ final public class MapPanel extends javax.swing.JPanel { private MapWaypoint currentlySelectedWaypoint; private Set currentlySelectedTrack; + static { + DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID()); + DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID()); + DOT_WAYPOINT_TYPES.add(ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID()); + } + /** * Creates new form MapPanel */ @@ -486,14 +497,30 @@ final public class MapPanel extends javax.swing.JPanel { Iterator iterator = waypoints.iterator(); - // These maybe the points closest to lat/log was clicked but - // that doesn't mean they are close in terms of pixles. + // These may be the points closest to the lat/lon location that was + // clicked, but that doesn't mean they are close in terms of pixles. List closestPoints = new ArrayList<>(); while (iterator.hasNext()) { MapWaypoint nextWaypoint = iterator.next(); - Point2D point = mapViewer.convertGeoPositionToPoint(nextWaypoint.getPosition()); - Rectangle rect = new Rectangle((int) point.getX() - (whiteWaypointImage.getWidth() / 2), (int) point.getY() - whiteWaypointImage.getHeight(), whiteWaypointImage.getWidth(), whiteWaypointImage.getHeight()); + int pointX = (int) point.getX(); + int pointY = (int) point.getY(); + Rectangle rect; + if (DOT_WAYPOINT_TYPES.contains(nextWaypoint.getArtifactTypeID())) { + rect = new Rectangle( + pointX - (DOT_SIZE / 2), + pointY - (DOT_SIZE / 2), + DOT_SIZE, + DOT_SIZE + ); + } else { + rect = new Rectangle( + pointX - (whiteWaypointImage.getWidth() / 2), + pointY - whiteWaypointImage.getHeight(), + whiteWaypointImage.getWidth(), + whiteWaypointImage.getHeight() + ); + } if (rect.contains(clickPoint)) { closestPoints.add(nextWaypoint); @@ -689,6 +716,7 @@ final public class MapPanel extends javax.swing.JPanel { if (waypoints.size() > 0) { MapWaypoint selection = waypoints.get(0); currentlySelectedWaypoint = selection; + currentlySelectedTrack = null; for (Set track : tracks) { if (track.contains(selection)) { currentlySelectedTrack = track; @@ -751,17 +779,16 @@ final public class MapPanel extends javax.swing.JPanel { * @return the new dot image */ private BufferedImage createTrackDotImage(Color color) { - int w = 10; - int h = 10; + int s = DOT_SIZE; - BufferedImage ret = new BufferedImage(w + 2, h + 2, BufferedImage.TYPE_INT_ARGB); + BufferedImage ret = new BufferedImage(s, s, BufferedImage.TYPE_INT_ARGB); Graphics2D g = ret.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setColor(color); - g.fillOval(1, 1, w, h); + g.fillOval(1, 1, s - 2, s - 2); g.setColor(Color.BLACK); g.setStroke(new BasicStroke(1)); - g.drawOval(1, 1, w, h); + g.drawOval(1, 1, s - 2, s - 2); g.dispose(); return ret; } @@ -794,14 +821,11 @@ final public class MapPanel extends javax.swing.JPanel { public void paintWaypoint(Graphics2D g, JXMapViewer map, MapWaypoint waypoint) { Color color = getColor(waypoint); BufferedImage image; - int artifactType = waypoint.getArtifactTypeID(); Point2D point = map.getTileFactory().geoToPixel(waypoint.getPosition(), map.getZoom()); int x = (int) point.getX(); int y = (int) point.getY(); - if (artifactType == ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() - || artifactType == ARTIFACT_TYPE.TSK_GPS_TRACK.getTypeID() - || artifactType == ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID()) { + if (DOT_WAYPOINT_TYPES.contains(waypoint.getArtifactTypeID())) { image = dotImageCache.computeIfAbsent(color, k -> { return createTrackDotImage(color); }); From 8388070213abde091557b7e8f251626c9bd442e2 Mon Sep 17 00:00:00 2001 From: Ethan Roseman Date: Tue, 21 Apr 2020 22:54:34 -0400 Subject: [PATCH 07/13] 6267 Improved exception handling --- .../org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index c78c822af0..6cf9720e48 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -523,7 +523,12 @@ class GeoFilterPanel extends javax.swing.JPanel { resultSet.next(); count = resultSet.getLong("count"); } catch (SQLException ex) { - Exceptions.printStackTrace(ex); + Throwable cause = ex.getCause(); + if (cause != null) { + logger.log(Level.SEVERE, cause.getMessage(), cause); + } else { + logger.log(Level.SEVERE, ex.getMessage(), ex); + } } } return count; From 2f66b2ba1c65778b4b96ec8ede047e8bb8441593 Mon Sep 17 00:00:00 2001 From: Ethan Roseman Date: Wed, 22 Apr 2020 11:11:18 -0400 Subject: [PATCH 08/13] 6267 Updating query to be more generic --- .../autopsy/geolocation/GeoFilterPanel.java | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index 6cf9720e48..5c07368b8f 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -37,7 +37,6 @@ import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.SpinnerNumberModel; import javax.swing.SwingWorker; -import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; @@ -486,36 +485,35 @@ class GeoFilterPanel extends javax.swing.JPanel { } /** - * Get a count of TSK_METADATA_EXIF artifacts containing GPS data for + * Get a count of artifacts of the given type containing GPS data for * the given data case and source. Does not include rejected artifacts. * * @param sleuthkitCase - * @param dataSourceID + * @param dataSource + * @param artifactType * * @return The artifacts count that match the criteria * * @throws TskCoreException */ - public long getExifGPSDataCount(SleuthkitCase sleuthkitCase, DataSource dataSource) throws TskCoreException { + public long getGPSDataCount(SleuthkitCase sleuthkitCase, + DataSource dataSource, BlackboardArtifact.ARTIFACT_TYPE artifactType) throws TskCoreException { long count = 0; String queryStr - = "SELECT count(*) AS count FROM" - + " (" - + " SELECT artifact_obj_id, group_concat(attribute_type_id) FROM" + = "SELECT count(DISTINCT artifact_id) AS count FROM" + " (" + " SELECT * FROM blackboard_artifacts as arts" + " INNER JOIN blackboard_attributes as attrs" + " ON attrs.artifact_id = arts.artifact_id" - + " WHERE arts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() + + " WHERE arts.artifact_type_id = " + artifactType.getTypeID() + " AND arts.data_source_obj_id = " + dataSource.getId() + " AND arts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() + " AND" + " (" + "attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID() + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID() + + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS.getTypeID() + " )" - + " )" - + "GROUP BY artifact_obj_id" + " )"; try (SleuthkitCase.CaseDbQuery queryResult = sleuthkitCase.executeQuery(queryStr)) { ResultSet resultSet = queryResult.getResultSet(); @@ -548,12 +546,7 @@ class GeoFilterPanel extends javax.swing.JPanel { private Map getGPSDataSources(SleuthkitCase sleuthkitCase, DataSource dataSource) throws TskCoreException { HashMap ret = new HashMap<>(); for (BlackboardArtifact.ARTIFACT_TYPE type : GPS_ARTIFACT_TYPES) { - long count; - if (type == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF) { - count = getExifGPSDataCount(sleuthkitCase, dataSource); - } else { - count = sleuthkitCase.getBlackboardArtifactsTypeCount(type.getTypeID(), dataSource.getId()); - } + long count = getGPSDataCount(sleuthkitCase, dataSource, type); if (count > 0) { ret.put(type, count); } From 541fb42bb852b193f2a6d6e398f85de028bd0212 Mon Sep 17 00:00:00 2001 From: Ethan Roseman Date: Thu, 23 Apr 2020 10:24:36 -0400 Subject: [PATCH 09/13] 6285 Codacy --- Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java index eea578b0c0..242d8e81d6 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/MapPanel.java @@ -88,7 +88,7 @@ final public class MapPanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(MapPanel.class.getName()); private static final long serialVersionUID = 1L; - private static final HashSet DOT_WAYPOINT_TYPES = new HashSet<>(); + private static final Set DOT_WAYPOINT_TYPES = new HashSet<>(); private static final int DOT_SIZE = 12; private boolean zoomChanging; From 36ced0b39113c1295607823a1d07a4e688c81d15 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 23 Apr 2020 10:37:38 -0400 Subject: [PATCH 10/13] improved logging --- .../sleuthkit/autopsy/communications/CommunicationsGraph.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java index 38a20d07e5..f07d4d52ab 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java +++ b/Core/src/org/sleuthkit/autopsy/communications/CommunicationsGraph.java @@ -209,7 +209,7 @@ final class CommunicationsGraph extends mxGraph { try { adiRelationshipsCount = commsManager.getRelationshipSourcesCount(accountDeviceInstance, currentFilter); } catch (TskCoreException tskCoreException) { - logger.log(Level.SEVERE, "Error", tskCoreException); + logger.log(Level.SEVERE, "There was an error fetching relationships for the node: " + accountDeviceInstance, tskCoreException); } double size = Math.sqrt(adiRelationshipsCount) + 10; From 0bd9a1bfa0bb2699955d437effc225ca24f88c97 Mon Sep 17 00:00:00 2001 From: Ethan Roseman Date: Thu, 23 Apr 2020 10:43:41 -0400 Subject: [PATCH 11/13] 6267 Codacy --- .../sleuthkit/autopsy/geolocation/GeoFilterPanel.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index 5c07368b8f..dcea91c93d 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -513,13 +513,14 @@ class GeoFilterPanel extends javax.swing.JPanel { + "attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID() + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID() + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS.getTypeID() + + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_WAYPOINTS.getTypeID() + " )" + " )"; try (SleuthkitCase.CaseDbQuery queryResult = sleuthkitCase.executeQuery(queryStr)) { - ResultSet resultSet = queryResult.getResultSet(); - try { - resultSet.next(); - count = resultSet.getLong("count"); + try (ResultSet resultSet = queryResult.getResultSet()) { + if (resultSet.next()) { + count = resultSet.getLong("count"); + } } catch (SQLException ex) { Throwable cause = ex.getCause(); if (cause != null) { From 11d9613bb34aeec61f6f24287d02cadc2502edc6 Mon Sep 17 00:00:00 2001 From: Ethan Roseman Date: Thu, 23 Apr 2020 10:52:45 -0400 Subject: [PATCH 12/13] 6267 Condense try-with-resources --- .../autopsy/geolocation/GeoFilterPanel.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index dcea91c93d..5f47502c58 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -516,18 +516,17 @@ class GeoFilterPanel extends javax.swing.JPanel { + " or attrs.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_WAYPOINTS.getTypeID() + " )" + " )"; - try (SleuthkitCase.CaseDbQuery queryResult = sleuthkitCase.executeQuery(queryStr)) { - try (ResultSet resultSet = queryResult.getResultSet()) { - if (resultSet.next()) { - count = resultSet.getLong("count"); - } - } catch (SQLException ex) { - Throwable cause = ex.getCause(); - if (cause != null) { - logger.log(Level.SEVERE, cause.getMessage(), cause); - } else { - logger.log(Level.SEVERE, ex.getMessage(), ex); - } + try (SleuthkitCase.CaseDbQuery queryResult = sleuthkitCase.executeQuery(queryStr); + ResultSet resultSet = queryResult.getResultSet()) { + if (resultSet.next()) { + count = resultSet.getLong("count"); + } + } catch (SQLException ex) { + Throwable cause = ex.getCause(); + if (cause != null) { + logger.log(Level.SEVERE, cause.getMessage(), cause); + } else { + logger.log(Level.SEVERE, ex.getMessage(), ex); } } return count; From 86a565d7edbed442c85e1383f0968cd53ecb5b1c Mon Sep 17 00:00:00 2001 From: Ethan Roseman Date: Fri, 24 Apr 2020 11:59:23 -0400 Subject: [PATCH 13/13] 6267: public -> private --- Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index 5f47502c58..d8121e68a1 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -496,7 +496,7 @@ class GeoFilterPanel extends javax.swing.JPanel { * * @throws TskCoreException */ - public long getGPSDataCount(SleuthkitCase sleuthkitCase, + private long getGPSDataCount(SleuthkitCase sleuthkitCase, DataSource dataSource, BlackboardArtifact.ARTIFACT_TYPE artifactType) throws TskCoreException { long count = 0; String queryStr