updates to use abstract waypoint fetcher

This commit is contained in:
Greg DiCristofaro 2020-12-07 13:31:07 -05:00
parent 5df1f63b46
commit db26c90bf7
4 changed files with 77 additions and 39 deletions

View File

@ -29,13 +29,15 @@ import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException; import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor; import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultArtifactUpdateGovernor;
import org.sleuthkit.autopsy.geolocation.AbstractWaypointFetcher;
import org.sleuthkit.autopsy.geolocation.GeoFilter;
import org.sleuthkit.autopsy.geolocation.MapWaypoint;
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult;
import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint;
import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder; import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
@ -45,11 +47,10 @@ import org.sleuthkit.datamodel.DataSource;
* Gathers summary data about Geolocation information for a data source. * Gathers summary data about Geolocation information for a data source.
*/ */
public class GeolocationSummary implements DefaultArtifactUpdateGovernor { public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
/** /**
* A count of hits for a particular city. * A count of hits for a particular city.
*/ */
public class CityRecordCount { public static class CityRecordCount {
private final CityRecord cityRecord; private final CityRecord cityRecord;
private final int count; private final int count;
@ -267,7 +268,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
* @return A pair where the left value is the total count of way points and * @return A pair where the left value is the total count of way points and
* the right is the total list of way points that are >= minTime. * the right is the total list of way points that are >= minTime.
*/ */
private Pair<Integer, Integer> getCounts(List<Waypoint> points, Long minTime) { private Pair<Integer, Integer> getCounts(List<MapWaypoint> points, Long minTime) {
if (points == null) { if (points == null) {
return EMPTY_COUNT; return EMPTY_COUNT;
@ -279,6 +280,9 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
(pair1, pair2) -> Pair.of(pair1.getLeft() + pair2.getLeft(), pair1.getRight() + pair2.getRight())); (pair1, pair2) -> Pair.of(pair1.getLeft() + pair2.getLeft(), pair1.getRight() + pair2.getRight()));
} }
private static final long DAY_SECS = 24 * 60 * 60;
/** /**
* Get this list of hits per city where the list is sorted descending by * Get this list of hits per city where the list is sorted descending by
* number of found hits (i.e. most hits is first index). * number of found hits (i.e. most hits is first index).
@ -294,14 +298,14 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
ClosestCityMapper closestCityMapper = ClosestCityMapper.getInstance(); ClosestCityMapper closestCityMapper = ClosestCityMapper.getInstance();
List<Waypoint> dataSourcePoints = getPoints(dataSource); List<MapWaypoint> dataSourcePoints = getPoints(dataSource);
Map<CityRecord, List<Waypoint>> allCityPoints = new HashMap<>(); Map<CityRecord, List<MapWaypoint>> allCityPoints = new HashMap<>();
List<Waypoint> others = new ArrayList<>(); List<MapWaypoint> others = new ArrayList<>();
Long mostRecent = null; Long mostRecent = null;
for (Waypoint pt : dataSourcePoints) { for (MapWaypoint pt : dataSourcePoints) {
CityRecord city = closestCityMapper.findClosest(new CityRecord(null, null, pt.getLatitude(), pt.getLongitude())); CityRecord city = closestCityMapper.findClosest(new CityRecord(null, null, pt.getX(), pt.getY()));
Long curTime = pt.getTimestamp(); Long curTime = pt.getTimestamp();
if (curTime != null && (mostRecent == null || curTime > mostRecent)) { if (curTime != null && (mostRecent == null || curTime > mostRecent)) {
mostRecent = curTime; mostRecent = curTime;
@ -310,7 +314,7 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
if (city == null) { if (city == null) {
others.add(pt); others.add(pt);
} else { } else {
List<Waypoint> cityPoints = allCityPoints.get(city); List<MapWaypoint> cityPoints = allCityPoints.get(city);
if (cityPoints == null) { if (cityPoints == null) {
cityPoints = new ArrayList<>(); cityPoints = new ArrayList<>();
allCityPoints.put(city, cityPoints); allCityPoints.put(city, cityPoints);
@ -320,11 +324,11 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
} }
} }
final Long mostRecentTime = mostRecent; final Long mostRecentMinTime = (mostRecent == null) ? null : mostRecent - daysCount * DAY_SECS;
// pair left is total count and right is count within range (or mostRecent is null) // pair left is total count and right is count within range (or mostRecent is null)
Map<CityRecord, Pair<Integer, Integer>> allCityCounts = allCityPoints.entrySet().stream() Map<CityRecord, Pair<Integer, Integer>> allCityCounts = allCityPoints.entrySet().stream()
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> getCounts(e.getValue(), mostRecentTime))); .collect(Collectors.toMap((e) -> e.getKey(), (e) -> getCounts(e.getValue(), mostRecentMinTime)));
List<CityRecordCount> mostCommonCounts = allCityCounts.entrySet().stream() List<CityRecordCount> mostCommonCounts = allCityCounts.entrySet().stream()
.map(e -> new CityRecordCount(e.getKey(), e.getValue().getLeft())) .map(e -> new CityRecordCount(e.getKey(), e.getValue().getLeft()))
@ -338,14 +342,55 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
.limit(maxCount) .limit(maxCount)
.collect(Collectors.toList()); .collect(Collectors.toList());
Pair<Integer, Integer> otherCounts = getCounts(others, mostRecentTime); Pair<Integer, Integer> otherCounts = getCounts(others, mostRecentMinTime);
int otherMostCommonCount = otherCounts.getLeft(); int otherMostCommonCount = otherCounts.getLeft();
int otherMostRecentCount = otherCounts.getRight(); int otherMostRecentCount = otherCounts.getRight();
return new CityData( return new CityData(
new CityCountsList(mostCommonCounts, otherMostCommonCount), new CityCountsList(mostCommonCounts, otherMostCommonCount),
new CityCountsList(mostRecentCounts, otherMostRecentCount), new CityCountsList(mostRecentCounts, otherMostRecentCount),
mostRecentTime); mostRecentMinTime);
}
/**
* Means of fetching points from geolocation.
*/
private static class PointFetcher extends AbstractWaypointFetcher {
private final BlockingQueue<List<MapWaypoint>> asyncResult;
/**
* Main constructor.
*
* @param asyncResult Geolocation fetches results in a callback which is
* already handled by other mechanisms in data source summary. The
* BlockingQueue blocks until a result is received from geolocation.
* @param filters The applicable filters for geolocation.
*/
public PointFetcher(BlockingQueue<List<MapWaypoint>> asyncResult, GeoFilter filters) {
super(filters);
this.asyncResult = asyncResult;
}
@Override
public void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks, List<Set<MapWaypoint>> areas, boolean wasEntirelySuccessful) {
Stream<List<Set<MapWaypoint>>> stream = Stream.of(
Arrays.asList(mapWaypoints),
tracks == null ? Collections.emptyList() : tracks,
areas == null ? Collections.emptyList() : areas);
List<MapWaypoint> wayPoints = stream
.flatMap((List<Set<MapWaypoint>> list) -> list.stream())
.flatMap((Set<MapWaypoint> set) -> set.stream())
.collect(Collectors.toList());
// push to blocking queue to continue
try {
asyncResult.put(wayPoints);
} catch (InterruptedException ignored) {
// ignored cancellations
}
}
} }
/** /**
@ -357,18 +402,12 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
* @throws GeoLocationDataException * @throws GeoLocationDataException
* @throws InterruptedException * @throws InterruptedException
*/ */
private List<Waypoint> getPoints(DataSource dataSource) throws SleuthkitCaseProviderException, GeoLocationDataException, InterruptedException { private List<MapWaypoint> getPoints(DataSource dataSource) throws SleuthkitCaseProviderException, GeoLocationDataException, InterruptedException {
// make asynchronous callback synchronous (the callback nature will be handled in a different level) // make asynchronous callback synchronous (the callback nature will be handled in a different level)
// see the following: https://stackoverflow.com/questions/20659961/java-synchronous-callback // see the following: https://stackoverflow.com/questions/20659961/java-synchronous-callback
final BlockingQueue<GeoLocationParseResult<Waypoint>> asyncResult = new ArrayBlockingQueue<>(1); final BlockingQueue<List<MapWaypoint>> asyncResult = new ArrayBlockingQueue<>(1);
final WaypointBuilder.WaypointFilterQueryCallBack callback = (result) -> { GeoFilter geoFilter = new GeoFilter(true, false, 0, Arrays.asList(dataSource), GPS_ARTIFACT_TYPES);
try {
asyncResult.put(result);
} catch (InterruptedException ignored) {
// ignored cancellations
}
};
WaypointBuilder.getAllWaypoints(provider.get(), WaypointBuilder.getAllWaypoints(provider.get(),
Arrays.asList(dataSource), Arrays.asList(dataSource),
@ -376,16 +415,8 @@ public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
true, true,
-1, -1,
false, false,
callback); new PointFetcher(asyncResult, geoFilter));
GeoLocationParseResult<Waypoint> result; return asyncResult.take();
result = asyncResult.take();
if (result.isSuccessfullyParsed()) {
return result.getItems();
} else {
return Collections.emptyList();
}
} }
} }

View File

@ -35,7 +35,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
/** /**
* The business logic for filtering waypoints. * The business logic for filtering waypoints.
*/ */
abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilterQueryCallBack { public abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilterQueryCallBack {
private static final Logger logger = Logger.getLogger(AbstractWaypointFetcher.class.getName()); private static final Logger logger = Logger.getLogger(AbstractWaypointFetcher.class.getName());
@ -46,7 +46,7 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
* *
* @param filters * @param filters
*/ */
AbstractWaypointFetcher(GeoFilter filters) { protected AbstractWaypointFetcher(GeoFilter filters) {
this.filters = filters; this.filters = filters;
} }
@ -79,7 +79,7 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
* @param tracks The tracks that were successfully parsed. * @param tracks The tracks that were successfully parsed.
* @param wasEntirelySuccessful True if no errors occurred while processing. * @param wasEntirelySuccessful True if no errors occurred while processing.
*/ */
abstract void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks, protected abstract void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks,
List<Set<MapWaypoint>> areas, boolean wasEntirelySuccessful); List<Set<MapWaypoint>> areas, boolean wasEntirelySuccessful);
@Override @Override

View File

@ -525,7 +525,7 @@ public final class GeolocationTopComponent extends TopComponent {
} }
@Override @Override
void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks, protected void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks,
List<Set<MapWaypoint>> areas, boolean wasEntirelySuccessful) { List<Set<MapWaypoint>> areas, boolean wasEntirelySuccessful) {
addWaypointsToMap(mapWaypoints, tracks, areas); addWaypointsToMap(mapWaypoints, tracks, areas);

View File

@ -63,7 +63,7 @@ import org.sleuthkit.datamodel.TskCoreException;
* *
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewer.viewer.Waypoint { public final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewer.viewer.Waypoint {
private static final Logger logger = Logger.getLogger(MapWaypoint.class.getName()); private static final Logger logger = Logger.getLogger(MapWaypoint.class.getName());
private final static String HTML_PROP_FORMAT = "<b>%s: </b>%s<br>"; private final static String HTML_PROP_FORMAT = "<b>%s: </b>%s<br>";
@ -366,6 +366,13 @@ final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewer.viewe
return getColor(dataModelWaypoint.getArtifact().getArtifactTypeID()); return getColor(dataModelWaypoint.getArtifact().getArtifactTypeID());
} }
/**
* @return The timestamp associated with this map way point or null.
*/
public Long getTimestamp() {
return dataModelWaypoint.getTimestamp();
}
/** /**
* An action class for Extracting artifact files. * An action class for Extracting artifact files.
*/ */