From 8364dc83ac0439fd7732426be637e2cfb8d77781 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 12 May 2020 15:52:53 -0400 Subject: [PATCH 01/17] fix so that getPointsList throws exception on null --- .../autopsy/geolocation/datamodel/Track.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java index 68da242b8a..7f077ab9ae 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java @@ -130,14 +130,15 @@ public final class Track extends GeoPath { */ private GeoTrackPoints getPointsList(Map attributeMap) throws GeoLocationDataException { BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS); - if (attribute != null) { - try { - return BlackboardJsonAttrUtil.fromAttribute(attribute, GeoTrackPoints.class); - } catch (InvalidJsonException ex) { - throw new GeoLocationDataException("Unable to parse track points in TSK_GEO_TRACKPOINTS attribute", ex); - } + if (attribute == null) { + throw new GeoLocationDataException("No TSK_GEO_TRACKPOINTS attribute present in attribute map to parse."); + } + + try { + return BlackboardJsonAttrUtil.fromAttribute(attribute, GeoTrackPoints.class); + } catch (InvalidJsonException ex) { + throw new GeoLocationDataException("Unable to parse track points in TSK_GEO_TRACKPOINTS attribute", ex); } - return null; } /** From d2bb1f8ef4aaadae8c2e3d7a22601213266a6be5 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 13 May 2020 10:07:33 -0400 Subject: [PATCH 02/17] working through bubbling exceptions --- .../geolocation/AbstractWaypointFetcher.java | 3 +- .../geolocation/datamodel/GeoPath.java | 12 +- .../datamodel/WaypointBuilder.java | 113 +++++++++++++----- .../autopsy/report/modules/kml/KMLReport.java | 13 +- 4 files changed, 108 insertions(+), 33 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java index 2c33d054cb..62c333d493 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java @@ -26,6 +26,7 @@ import javafx.util.Pair; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; +import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult; import org.sleuthkit.autopsy.geolocation.datamodel.Track; import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint; import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder; @@ -80,7 +81,7 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter @Override public void process(List waypoints) { - List tracks = new ArrayList<>(); + List> tracks = new ArrayList<>(); if (filters.getArtifactTypes().contains(ARTIFACT_TYPE.TSK_GPS_TRACK)) { try { tracks = Track.getTracks(Case.getCurrentCase().getSleuthkitCase(), filters.getDataSources()); diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java index 99b5db351f..4e7086a30c 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java @@ -74,15 +74,19 @@ public class GeoPath { * * @throws GeoLocationDataException */ - static public List getTracks(SleuthkitCase skCase, List sourceList) throws GeoLocationDataException { + public static List> getTracks(SleuthkitCase skCase, List sourceList) throws GeoLocationDataException { List artifacts = null; - List tracks = new ArrayList<>(); + List> tracks = new ArrayList<>(); try { artifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACK); for (BlackboardArtifact artifact : artifacts) { if (sourceList == null || sourceList.contains(artifact.getDataSource())) { - Track route = new Track(artifact); - tracks.add(route); + try { + Track route = new Track(artifact); + tracks.add(GeoLocationParseResult.create(route)); + } catch (GeoLocationDataException e) { + tracks.add(GeoLocationParseResult.error(e)); + } } } } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java index 11ff0107dd..d8910d5ac3 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java @@ -22,8 +22,12 @@ package org.sleuthkit.autopsy.geolocation.datamodel; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.logging.Level; +import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -40,15 +44,15 @@ import org.sleuthkit.datamodel.DataSource; public final class WaypointBuilder { private static final Logger logger = Logger.getLogger(WaypointBuilder.class.getName()); - - private final static String TIME_TYPE_IDS = String.format("%d, %d", - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), + + private final static String TIME_TYPE_IDS = String.format("%d, %d", + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID()); - - private final static String GEO_ATTRIBUTE_TYPE_IDS = String.format("%d, %d, %d", - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START.getTypeID(), - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_WAYPOINTS.getTypeID()); + + private final static String GEO_ATTRIBUTE_TYPE_IDS = String.format("%d, %d, %d", + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START.getTypeID(), + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_WAYPOINTS.getTypeID()); // SELECT statement for getting a list of waypoints where %s is a comma separated list // of attribute type ids. @@ -96,7 +100,7 @@ public final class WaypointBuilder { /** * This function will be called after the waypoints have been filtered. * - * @param wwaypoints This of waypoints. + * @param waypoints The list of waypoints determined. */ void process(List waypoints); } @@ -478,7 +482,7 @@ public final class WaypointBuilder { skCase.getCaseDbAccessManager().select(query, new CaseDbAccessManager.CaseDbAccessQueryCallback() { @Override public void process(ResultSet rs) { - List waypoints = new ArrayList<>(); + List> waypointResults = new ArrayList<>(); try { while (rs.next()) { int artifact_type_id = rs.getInt("artifact_type_id"); //NON-NLS @@ -486,12 +490,25 @@ public final class WaypointBuilder { ARTIFACT_TYPE type = ARTIFACT_TYPE.fromID(artifact_type_id); if (artifactTypes.contains(type)) { - waypoints.addAll(getWaypointForArtifact(skCase.getBlackboardArtifact(artifact_id), type)); + waypointResults.addAll(getWaypointForArtifact(skCase.getBlackboardArtifact(artifact_id), type)); } } + + List waypoints = new ArrayList<>(); + List> errors = new ArrayList<>(); + for (GeoLocationParseResult result : waypointResults) { + if (result.isSuccessfullyParsed()) { + waypoints.add(result.getGeoLocationObject()); + } else { + errors.add(result); + } + } + + handleErrors(errors); + queryCallBack.process(waypoints); - } catch (GeoLocationDataException | SQLException | TskCoreException ex) { + } catch (SQLException | TskCoreException ex) { logger.log(Level.WARNING, "Failed to filter waypoint.", ex); //NON-NLS } @@ -522,7 +539,7 @@ public final class WaypointBuilder { // FROM blackboard_attributes // WHERE attribute_type_id IN (%d, %d) return String.format(SELECT_WO_TIMESTAMP, - String.format(GEO_ARTIFACT_QUERY_ID_ONLY,TIME_TYPE_IDS), + String.format(GEO_ARTIFACT_QUERY_ID_ONLY, TIME_TYPE_IDS), getWaypointListQuery(dataSources)); } @@ -619,6 +636,52 @@ public final class WaypointBuilder { dataSourceList); } + /** + * A parser that could throw a GeoLocationDataException when there is a + * parse issue. + * + * @param The return type. + */ + private interface ParserWithError { + + T parse() throws GeoLocationDataException; + } + + /** + * Parses one waypoint. + * + * @param parser The parser to use. + * + * @return Returns a parse result that is either successful with a parsed + * waypoint or unsuccessful with an exception. + */ + private static GeoLocationParseResult parseWaypoint(ParserWithError parser) { + try { + return GeoLocationParseResult.create(parser.parse()); + } catch (GeoLocationDataException ex) { + return GeoLocationParseResult.error(ex); + } + } + + /** + * Parses a list of waypoints. + * + * @param parser The parser to use. + * + * @return Returns a list of parse results with the successfully parsed + * items or a list with one item indicating the failure. + */ + private static List> parseWaypoints(ParserWithError> parser) { + try { + return parser.parse().stream() + .map(GeoLocationParseResult::create) + .collect(Collectors.toList()); + + } catch (GeoLocationDataException ex) { + return Arrays.asList(GeoLocationParseResult.error(ex)); + } + } + /** * Create a Waypoint object for the given Blackboard artifact. * @@ -626,37 +689,33 @@ public final class WaypointBuilder { * @param type The type of artifact * * @return A new waypoint object - * - * @throws GeoLocationDataException */ - static private List getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type) throws GeoLocationDataException { - List waypoints = new ArrayList<>(); + private static List> getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type) { + List> waypoints = new ArrayList<>(); switch (type) { case TSK_METADATA_EXIF: - waypoints.add(new EXIFWaypoint(artifact)); + waypoints.add(parseWaypoint(() -> new EXIFWaypoint(artifact))); break; case TSK_GPS_BOOKMARK: - waypoints.add(new BookmarkWaypoint(artifact)); + waypoints.add(parseWaypoint(() -> new BookmarkWaypoint(artifact))); break; case TSK_GPS_TRACKPOINT: - waypoints.add(new TrackpointWaypoint(artifact)); + waypoints.add(parseWaypoint(() -> new TrackpointWaypoint(artifact))); break; case TSK_GPS_SEARCH: - waypoints.add(new SearchWaypoint(artifact)); + waypoints.add(parseWaypoint(() -> new SearchWaypoint(artifact))); break; case TSK_GPS_ROUTE: - Route route = new Route(artifact); - waypoints.addAll(route.getRoute()); + waypoints.addAll(parseWaypoints(() -> new Route(artifact).getRoute())); break; case TSK_GPS_LAST_KNOWN_LOCATION: - waypoints.add(new LastKnownWaypoint(artifact)); + waypoints.add(parseWaypoint(() -> new LastKnownWaypoint(artifact))); break; case TSK_GPS_TRACK: - Track track = new Track(artifact); - waypoints.addAll(track.getPath()); + waypoints.addAll(parseWaypoints(() -> new Track(artifact).getPath())); break; default: - waypoints.add(new CustomArtifactWaypoint(artifact)); + waypoints.add(parseWaypoint(() -> new CustomArtifactWaypoint(artifact))); } return waypoints; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java index c13f385ba3..7e9217db38 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java @@ -33,6 +33,7 @@ import java.io.OutputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import org.jdom2.Document; @@ -45,6 +46,7 @@ import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; 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.Route; import org.sleuthkit.autopsy.geolocation.datamodel.Track; @@ -483,7 +485,16 @@ public final class KMLReport implements GeneralReportModule { List tracks = null; if (waypointList == null) { - tracks = Track.getTracks(skCase, null); + List> result = Track.getTracks(skCase, null); + tracks = new ArrayList<>(); + for (GeoLocationParseResult parseResult : result) { + if (parseResult.isSuccessfullyParsed()) { + tracks.add(parseResult.getGeoLocationObject()); + } else { + logError(); + } + } + } else { tracks = WaypointBuilder.getTracks(waypointList); } From bfea649c48de72e205c301a753e390cef8fe3c23 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 13 May 2020 10:07:54 -0400 Subject: [PATCH 03/17] working through bubbling exceptions --- .../datamodel/GeoLocationParseResult.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java new file mode 100644 index 0000000000..06ee7854d4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java @@ -0,0 +1,87 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.geolocation.datamodel; + +/** + * The result of attempting to parse a GeoLocation object. + */ +public class GeoLocationParseResult { + + private final boolean successfullyParsed; + private final GeoLocationDataException exception; + private final T geoObject; + + private GeoLocationParseResult(boolean successfullyParsed, GeoLocationDataException exception, T geoObject) { + this.successfullyParsed = successfullyParsed; + this.exception = exception; + this.geoObject = geoObject; + } + + /** + * Creates a GeoLocationParseResult as the result of a successful parse. + * + * @param The type of object to parse. + * @param geoObject The GeoLocation object to include in result. + * + * @return The generated WaypointParseResult. + */ + public static GeoLocationParseResult create(T geoObject) { + if (geoObject == null) { + return new GeoLocationParseResult(false, new GeoLocationDataException("GeoLocation object provided was null"), null); + } + + return new GeoLocationParseResult(true, null, geoObject); + } + + /** + * Creates a GeoLocationParseResult indicating a failed parsing. + * + * @param The type of GeoLocation object that was supposed to be parsed. + * @param exception The exception generated. + * + * @return The GeoLocationParseResult indicating an error. + */ + public static GeoLocationParseResult error(GeoLocationDataException exception) { + return new GeoLocationParseResult(false, exception, null); + } + + /** + * Whether or not the GeoLocation object has been successfully parsed. If true, there + * should be a non-null GeoLocation object present. Otherwise, there should be a non-null exception. + * + * @return Whether or not the GeoLocation object has been successfully parsed. + */ + public boolean isSuccessfullyParsed() { + return successfullyParsed; + } + + /** + * @return The exception caused in attempting to parse the GeoLocation object if there was an exception. + */ + public GeoLocationDataException getException() { + return exception; + } + + /** + * @return The parsed GeoLocation object if the waypoint was successfully parsed. + */ + public T getGeoLocationObject() { + return geoObject; + } +} From ae739966c3b76fc041905ea1b32eb3c818aca05f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 13 May 2020 12:26:53 -0400 Subject: [PATCH 04/17] provided context in parse result for error messages; error messages need to be handled in GeolocationTopComponent and KMLReport now --- .../geolocation/AbstractWaypointFetcher.java | 19 ++- .../geolocation/GeolocationTopComponent.java | 7 +- .../datamodel/GeoLocationParseResult.java | 111 +++++++++++++++--- .../geolocation/datamodel/GeoPath.java | 4 +- .../datamodel/WaypointBuilder.java | 52 ++++---- .../autopsy/report/modules/kml/KMLReport.java | 14 +-- 6 files changed, 141 insertions(+), 66 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java index 62c333d493..eb0371bdae 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java @@ -27,6 +27,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult; +import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult.SeparationResult; import org.sleuthkit.autopsy.geolocation.datamodel.Track; import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint; import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder; @@ -77,19 +78,25 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter * * @param mapWaypoints List of filtered MapWaypoints. */ - abstract void handleFilteredWaypointSet(Set mapWaypoints, List> tracks); + abstract void handleFilteredWaypointSet(Set mapWaypoints, List> tracks, + List> failedTracks, List> failedWaypoints); @Override - public void process(List waypoints) { - List> tracks = new ArrayList<>(); + public void process(List> waypointResults) { + List> trackResults = new ArrayList<>(); if (filters.getArtifactTypes().contains(ARTIFACT_TYPE.TSK_GPS_TRACK)) { try { - tracks = Track.getTracks(Case.getCurrentCase().getSleuthkitCase(), filters.getDataSources()); + trackResults = Track.getTracks(Case.getCurrentCase().getSleuthkitCase(), filters.getDataSources()); } catch (GeoLocationDataException ex) { logger.log(Level.WARNING, "Exception thrown while retrieving list of Tracks", ex); } } - Pair, List>> waypointsAndTracks = createWaypointList(waypoints, tracks); + + SeparationResult separatedWaypoints = GeoLocationParseResult.separate(waypointResults); + SeparationResult separatedTracks = GeoLocationParseResult.separate(trackResults); + + Pair, List>> waypointsAndTracks = + createWaypointList(separatedWaypoints.getParsedItems(), separatedTracks.getParsedItems()); final Set pointSet = MapWaypoint.getWaypoints(waypointsAndTracks.getKey()); final List> trackSets = new ArrayList<>(); @@ -97,7 +104,7 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter trackSets.add(MapWaypoint.getWaypoints(t)); } - handleFilteredWaypointSet(pointSet, trackSets); + handleFilteredWaypointSet(pointSet, trackSets, separatedTracks.getFailedItems(), separatedWaypoints.getFailedItems()); } /** diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java index ae387c7847..116a20d14d 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java @@ -50,6 +50,9 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.geolocation.GeoFilterPanel.GeoFilter; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; +import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult; +import org.sleuthkit.autopsy.geolocation.datamodel.Track; +import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint; import org.sleuthkit.autopsy.ingest.IngestManager; import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -501,8 +504,10 @@ public final class GeolocationTopComponent extends TopComponent { } @Override - void handleFilteredWaypointSet(Set mapWaypoints, List> tracks) { + void handleFilteredWaypointSet(Set mapWaypoints, List> tracks, + List> failedTracks, List> failedWaypoints) { addWaypointsToMap(mapWaypoints, tracks); + handleErrors(failedTracks, failedWaypoints); } } } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java index 06ee7854d4..67438b7275 100644 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java @@ -18,6 +18,11 @@ */ package org.sleuthkit.autopsy.geolocation.datamodel; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.collections4.ListUtils; +import org.sleuthkit.datamodel.BlackboardArtifact; + /** * The result of attempting to parse a GeoLocation object. */ @@ -25,63 +30,137 @@ public class GeoLocationParseResult { private final boolean successfullyParsed; private final GeoLocationDataException exception; + private final BlackboardArtifact artifact; private final T geoObject; - private GeoLocationParseResult(boolean successfullyParsed, GeoLocationDataException exception, T geoObject) { + GeoLocationParseResult(BlackboardArtifact artifact, + boolean successfullyParsed, GeoLocationDataException exception, T geoObject) { + this.successfullyParsed = successfullyParsed; this.exception = exception; + this.artifact = artifact; this.geoObject = geoObject; } /** * Creates a GeoLocationParseResult as the result of a successful parse. - * - * @param The type of object to parse. - * @param geoObject The GeoLocation object to include in result. + * @param The type of object to parse. + * @param artifact The artifact that was parsed or failed in parsing + * (could be null). + * @param geoObject The GeoLocation object to include in result. * * @return The generated WaypointParseResult. */ - public static GeoLocationParseResult create(T geoObject) { + public static GeoLocationParseResult create(BlackboardArtifact artifact, T geoObject) { if (geoObject == null) { - return new GeoLocationParseResult(false, new GeoLocationDataException("GeoLocation object provided was null"), null); + return new GeoLocationParseResult(artifact, false, new GeoLocationDataException("GeoLocation object provided was null"), null); } - return new GeoLocationParseResult(true, null, geoObject); + return new GeoLocationParseResult(artifact, true, null, geoObject); } /** * Creates a GeoLocationParseResult indicating a failed parsing. * - * @param The type of GeoLocation object that was supposed to be parsed. - * @param exception The exception generated. + * @param The type of GeoLocation object that was supposed to + * be parsed. + * @param artifact The artifact that was parsed or failed in parsing + * (could be null). + * @param exception The exception generated. * * @return The GeoLocationParseResult indicating an error. */ - public static GeoLocationParseResult error(GeoLocationDataException exception) { - return new GeoLocationParseResult(false, exception, null); + public static GeoLocationParseResult error(BlackboardArtifact artifact, GeoLocationDataException exception) { + return new GeoLocationParseResult(artifact, false, exception, null); } /** - * Whether or not the GeoLocation object has been successfully parsed. If true, there - * should be a non-null GeoLocation object present. Otherwise, there should be a non-null exception. + * The result of splitting an iterable of GeoLocationParseResults into a + * list of successfully parsed items and a list of failures. * - * @return Whether or not the GeoLocation object has been successfully parsed. + * @param The parsed item type. + */ + public static class SeparationResult { + + private final List> failedItems; + private final List parsedItems; + + SeparationResult(List> failedItems, List parsedItems) { + this.failedItems = failedItems; + this.parsedItems = parsedItems; + } + + /** + * @return The items that failed to parse properly. + */ + public List> getFailedItems() { + return failedItems; + } + + /** + * @return The underlying items that were successfully parsed. + */ + public List getParsedItems() { + return parsedItems; + } + } + + /** + * Separates an iterable of GeoLocationParseResult objects into failed items + * and successfully parsed items. + * + * @param The underlying type that was parsed. + * @param items The items to separate. + * + * @return The SeparationResult with successfully parsed and failed items. + */ + public static SeparationResult separate(Iterable> items) { + List> failedItems = new ArrayList<>(); + List parsedItems = new ArrayList<>(); + for (GeoLocationParseResult item : items) { + if (item.isSuccessfullyParsed()) { + parsedItems.add(item.getGeoLocationObject()); + } else { + failedItems.add(item); + } + } + + return new SeparationResult(ListUtils.unmodifiableList(failedItems), ListUtils.unmodifiableList(parsedItems)); + } + + /** + * Whether or not the GeoLocation object has been successfully parsed. If + * true, there should be a non-null GeoLocation object present. Otherwise, + * there should be a non-null exception. + * + * @return Whether or not the GeoLocation object has been successfully + * parsed. */ public boolean isSuccessfullyParsed() { return successfullyParsed; } /** - * @return The exception caused in attempting to parse the GeoLocation object if there was an exception. + * @return The exception caused in attempting to parse the GeoLocation + * object if there was an exception. */ public GeoLocationDataException getException() { return exception; } /** - * @return The parsed GeoLocation object if the waypoint was successfully parsed. + * @return The parsed GeoLocation object if the waypoint was successfully + * parsed. */ public T getGeoLocationObject() { return geoObject; } + + /** + * @return The artifact that was parsed or failed in parsing (could be + * null). + */ + public BlackboardArtifact getArtifact() { + return artifact; + } } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java index 4e7086a30c..d6b61f24d3 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java @@ -83,9 +83,9 @@ public class GeoPath { if (sourceList == null || sourceList.contains(artifact.getDataSource())) { try { Track route = new Track(artifact); - tracks.add(GeoLocationParseResult.create(route)); + tracks.add(GeoLocationParseResult.create(artifact,route)); } catch (GeoLocationDataException e) { - tracks.add(GeoLocationParseResult.error(e)); + tracks.add(GeoLocationParseResult.error(artifact, e)); } } } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java index d8910d5ac3..2188af8e48 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java @@ -102,7 +102,7 @@ public final class WaypointBuilder { * * @param waypoints The list of waypoints determined. */ - void process(List waypoints); + void process(List> waypoints); } /** @@ -494,20 +494,8 @@ public final class WaypointBuilder { } } - - List waypoints = new ArrayList<>(); - List> errors = new ArrayList<>(); - for (GeoLocationParseResult result : waypointResults) { - if (result.isSuccessfullyParsed()) { - waypoints.add(result.getGeoLocationObject()); - } else { - errors.add(result); - } - } - - handleErrors(errors); - - queryCallBack.process(waypoints); + + queryCallBack.process(waypointResults); } catch (SQLException | TskCoreException ex) { logger.log(Level.WARNING, "Failed to filter waypoint.", ex); //NON-NLS } @@ -644,22 +632,23 @@ public final class WaypointBuilder { */ private interface ParserWithError { - T parse() throws GeoLocationDataException; + T parse(BlackboardArtifact artifact) throws GeoLocationDataException; } /** * Parses one waypoint. * * @param parser The parser to use. + * @param artifact The artifact to be parsed. * * @return Returns a parse result that is either successful with a parsed * waypoint or unsuccessful with an exception. */ - private static GeoLocationParseResult parseWaypoint(ParserWithError parser) { + private static GeoLocationParseResult parseWaypoint(ParserWithError parser, BlackboardArtifact artifact) { try { - return GeoLocationParseResult.create(parser.parse()); + return GeoLocationParseResult.create(artifact, parser.parse(artifact)); } catch (GeoLocationDataException ex) { - return GeoLocationParseResult.error(ex); + return GeoLocationParseResult.error(artifact, ex); } } @@ -667,18 +656,19 @@ public final class WaypointBuilder { * Parses a list of waypoints. * * @param parser The parser to use. + * @param artifact The artifact to be parsed. * * @return Returns a list of parse results with the successfully parsed * items or a list with one item indicating the failure. */ - private static List> parseWaypoints(ParserWithError> parser) { + private static List> parseWaypoints(ParserWithError> parser, BlackboardArtifact artifact) { try { - return parser.parse().stream() - .map(GeoLocationParseResult::create) + return parser.parse(artifact).stream() + .map((result) -> GeoLocationParseResult.create(artifact, result)) .collect(Collectors.toList()); } catch (GeoLocationDataException ex) { - return Arrays.asList(GeoLocationParseResult.error(ex)); + return Arrays.asList(GeoLocationParseResult.error(artifact, ex)); } } @@ -694,28 +684,28 @@ public final class WaypointBuilder { List> waypoints = new ArrayList<>(); switch (type) { case TSK_METADATA_EXIF: - waypoints.add(parseWaypoint(() -> new EXIFWaypoint(artifact))); + waypoints.add(parseWaypoint((a) -> new EXIFWaypoint(a), artifact)); break; case TSK_GPS_BOOKMARK: - waypoints.add(parseWaypoint(() -> new BookmarkWaypoint(artifact))); + waypoints.add(parseWaypoint((a) -> new BookmarkWaypoint(a), artifact)); break; case TSK_GPS_TRACKPOINT: - waypoints.add(parseWaypoint(() -> new TrackpointWaypoint(artifact))); + waypoints.add(parseWaypoint((a) -> new TrackpointWaypoint(a), artifact)); break; case TSK_GPS_SEARCH: - waypoints.add(parseWaypoint(() -> new SearchWaypoint(artifact))); + waypoints.add(parseWaypoint((a) -> new SearchWaypoint(a), artifact)); break; case TSK_GPS_ROUTE: - waypoints.addAll(parseWaypoints(() -> new Route(artifact).getRoute())); + waypoints.addAll(parseWaypoints((a) -> new Route(a).getRoute(), artifact)); break; case TSK_GPS_LAST_KNOWN_LOCATION: - waypoints.add(parseWaypoint(() -> new LastKnownWaypoint(artifact))); + waypoints.add(parseWaypoint((a) -> new LastKnownWaypoint(a), artifact)); break; case TSK_GPS_TRACK: - waypoints.addAll(parseWaypoints(() -> new Track(artifact).getPath())); + waypoints.addAll(parseWaypoints((a) -> new Track(a).getPath(), artifact)); break; default: - waypoints.add(parseWaypoint(() -> new CustomArtifactWaypoint(artifact))); + waypoints.add(parseWaypoint((a) -> new CustomArtifactWaypoint(a), artifact)); } return waypoints; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java index 7e9217db38..f5b20800a9 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java @@ -47,6 +47,7 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult; +import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult.SeparationResult; import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint; import org.sleuthkit.autopsy.geolocation.datamodel.Route; import org.sleuthkit.autopsy.geolocation.datamodel.Track; @@ -485,16 +486,9 @@ public final class KMLReport implements GeneralReportModule { List tracks = null; if (waypointList == null) { - List> result = Track.getTracks(skCase, null); - tracks = new ArrayList<>(); - for (GeoLocationParseResult parseResult : result) { - if (parseResult.isSuccessfullyParsed()) { - tracks.add(parseResult.getGeoLocationObject()); - } else { - logError(); - } - } - + SeparationResult result = GeoLocationParseResult.separate(Track.getTracks(skCase, null)); + tracks = result.getParsedItems(); + handleErrors(result.getFailedItems()); } else { tracks = WaypointBuilder.getTracks(waypointList); } From 91e543a59067ca0d9bd5748c34ed49c016ea0463 Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 25 May 2020 12:13:41 -0400 Subject: [PATCH 05/17] Test to see if new content has an extension before processing and ensure key creation is performed on a different thread. --- .../datamodel/FileTypesByExtension.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 344a24cb79..83b05019ca 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -43,6 +43,8 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.ModuleContentEvent; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -94,6 +96,25 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString()) || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { + + /** + * If a new file has been added but does not have an extension + * there is nothing to do. + */ + if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { + if ((evt.getOldValue() instanceof ModuleContentEvent) == false) { + return; + } + ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue(); + if ((moduleContentEvent.getSource() instanceof AbstractFile) == false) { + return; + } + AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource(); + if (abstractFile.getNameExtension().isEmpty()) { + return; + } + } + /** * Checking for a current case is a stop gap measure until a * different way of handling the closing of cases is worked @@ -415,7 +436,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { @Override public void update(Observable o, Object arg) { - refresh(true); + refresh(false); } @Override From 22a8b8bcdf07f4b5d4c4c8eac101a8fc28374150 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 27 May 2020 15:31:47 -0400 Subject: [PATCH 06/17] updates to handle errors --- .../geolocation/GeolocationTopComponent.java | 13 ++++++++++++- .../geolocation/datamodel/GeoPath.java | 4 +++- .../autopsy/report/modules/kml/KMLReport.java | 19 ++++++++++++++----- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java index 116a20d14d..d7da9c0df4 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java @@ -497,6 +497,10 @@ public final class GeolocationTopComponent extends TopComponent { * Extends AbstractWaypointFetcher to handle the returning of * the filters set of MapWaypoints. */ + @Messages({ + "GeolocationTopComponent.WaypointFetcher.onErrorTitle=Error gathering GPS Track Data", + "GeolocationTopComponent.WaypointFetcher.onErrorDescription=There was an error gathering some GPS Track Data. Some results have been excluded." + }) final private class WaypointFetcher extends AbstractWaypointFetcher { WaypointFetcher(GeoFilter filters) { @@ -507,7 +511,14 @@ public final class GeolocationTopComponent extends TopComponent { void handleFilteredWaypointSet(Set mapWaypoints, List> tracks, List> failedTracks, List> failedWaypoints) { addWaypointsToMap(mapWaypoints, tracks); - handleErrors(failedTracks, failedWaypoints); + + // if there is an error, present to the user. + if ((failedTracks != null && !failedTracks.isEmpty()) || (failedWaypoints != null && !failedWaypoints.isEmpty())) { + JOptionPane.showMessageDialog(GeolocationTopComponent.this, + Bundle.GeolocationTopComponent_WaypointFetcher_onErrorDescription(), + Bundle.GeolocationTopComponent_WaypointFetcher_onErrorTitle(), + JOptionPane.ERROR_MESSAGE); + } } } } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java index 5a666418fd..48bff3c69c 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java @@ -22,16 +22,18 @@ package org.sleuthkit.autopsy.geolocation.datamodel; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.logging.Level; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.coreutils.Logger; /** * Class representing a series of waypoints that form a path. */ public class GeoPath { - + private static final Logger LOGGER = Logger.getLogger(GeoPath.class.getName()); private final List waypointList; private final String pathName; private final BlackboardArtifact artifact; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java index 7905bbd1d3..201e9ef84a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java @@ -211,7 +211,11 @@ public final class KMLReport implements GeneralReportModule { try { makeRoutes(skCase); - makeTracks(skCase); + List> errors = makeTracks(skCase); + if (!errors.isEmpty()) { + result = ReportProgressPanel.ReportStatus.ERROR; + } + addLocationsToReport(skCase, baseReportDir); } catch (GeoLocationDataException | IOException | TskCoreException ex) { errorMessage = "Failed to complete report."; @@ -518,18 +522,21 @@ public final class KMLReport implements GeneralReportModule { * Add the track to the track folder in the document. * * @param skCase Currently open case. - * + * @return The items that could not be parsed appropriately. + * * @throws TskCoreException */ - void makeTracks(SleuthkitCase skCase) throws GeoLocationDataException, TskCoreException { + List> makeTracks(SleuthkitCase skCase) throws GeoLocationDataException, TskCoreException { List tracks = null; - + List> failedItems; + if (waypointList == null) { SeparationResult result = GeoLocationParseResult.separate(Track.getTracks(skCase, null)); tracks = result.getParsedItems(); - handleErrors(result.getFailedItems()); + failedItems = result.getFailedItems(); } else { tracks = WaypointBuilder.getTracks(waypointList); + failedItems = new ArrayList<>(); } for (Track track : tracks) { @@ -538,6 +545,8 @@ public final class KMLReport implements GeneralReportModule { } addTrackToReport(track); } + + return failedItems; } /** From d76e89413fdb82138842801c3c3644d58418c40f Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 27 May 2020 15:38:04 -0400 Subject: [PATCH 07/17] adding logging --- .../org/sleuthkit/autopsy/geolocation/datamodel/Track.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java index 7f077ab9ae..af19623100 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java @@ -22,18 +22,21 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil.InvalidJsonException; import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints; +import org.sleuthkit.autopsy.coreutils.Logger; /** * A GPS track with which wraps the TSK_GPS_TRACK artifact. */ public final class Track extends GeoPath { - + private static final Logger LOGGER = Logger.getLogger(Track.class.getName()); + private final Long startTimestamp; private final Long endTimeStamp; @@ -131,12 +134,14 @@ public final class Track extends GeoPath { private GeoTrackPoints getPointsList(Map attributeMap) throws GeoLocationDataException { BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS); if (attribute == null) { + LOGGER.log(Level.SEVERE, "No TSK_GEO_TRACKPOINTS attribute was present on the artifact."); throw new GeoLocationDataException("No TSK_GEO_TRACKPOINTS attribute present in attribute map to parse."); } try { return BlackboardJsonAttrUtil.fromAttribute(attribute, GeoTrackPoints.class); } catch (InvalidJsonException ex) { + LOGGER.log(Level.SEVERE, "TSK_GEO_TRACKPOINTS could not be properly parsed from TSK_GEO_TRACKPOINTS attribute."); throw new GeoLocationDataException("Unable to parse track points in TSK_GEO_TRACKPOINTS attribute", ex); } } From f6eee251677094eecc016474b7d2849bbe250621 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 28 May 2020 10:39:29 -0400 Subject: [PATCH 08/17] kml error report message --- .../autopsy/report/modules/kml/Bundle.properties-MERGED | 2 ++ .../org/sleuthkit/autopsy/report/modules/kml/KMLReport.java | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/kml/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/kml/Bundle.properties-MERGED index b97907cce9..c1fe7e6ac1 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/kml/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/kml/Bundle.properties-MERGED @@ -2,6 +2,7 @@ KMLReport.bookmarkError=Could not extract Bookmark information. # {0} - filePath KMLReport.errorGeneratingReport=Error adding {0} to case as a report. KMLReport.exifPhotoError=Could not extract photos with EXIF metadata. +KMLReport.failedToCompleteReport=Failed to complete report. KMLReport.gpsBookmarkError=Could not get GPS Bookmarks from database. KMLReport.gpsRouteDatabaseError=Could not get GPS Routes from database. KMLReport.gpsRouteError=Could not extract GPS Route information. @@ -9,6 +10,7 @@ KMLReport.gpsSearchDatabaseError=Could not get GPS Searches from database. KMLReport.kmlFileWriteError=Could not write the KML file. KMLReport.locationDatabaseError=Could not get GPS Last Known Location from database. KMLReport.locationError=Could not extract Last Known Location information. +KMLReport.partialFailure=There was an error creating the report. Some items were not exported. KMLReport.stylesheetError=Error placing KML stylesheet. The .KML file will not function properly. KMLReport.trackpointDatabaseError=Could not get GPS Trackpoints from database. KMLReport.trackpointError=Could not extract Trackpoint information. diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java index 201e9ef84a..a4d67313eb 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java @@ -129,6 +129,8 @@ public final class KMLReport implements GeneralReportModule { * @param waypointList */ @Messages({ + "KMLReport.failedToCompleteReport=Failed to complete report.", + "KMLReport.partialFailure=There was an error creating the report. Some items were not exported.", "KMLReport.unableToExtractPhotos=Could not extract photo information.", "KMLReport.exifPhotoError=Could not extract photos with EXIF metadata.", "KMLReport.bookmarkError=Could not extract Bookmark information.", @@ -214,11 +216,12 @@ public final class KMLReport implements GeneralReportModule { List> errors = makeTracks(skCase); if (!errors.isEmpty()) { result = ReportProgressPanel.ReportStatus.ERROR; + errorMessage = Bundle.KMLReport_partialFailure(); } addLocationsToReport(skCase, baseReportDir); } catch (GeoLocationDataException | IOException | TskCoreException ex) { - errorMessage = "Failed to complete report."; + errorMessage = Bundle.KMLReport_failedToCompleteReport(); logger.log(Level.SEVERE, errorMessage, ex); //NON-NLS result = ReportProgressPanel.ReportStatus.ERROR; } From 5b3503f5601a73d0ddbc3180957c9d2529997e12 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 28 May 2020 11:30:29 -0400 Subject: [PATCH 09/17] fix to prevent exceptions from bubbling up from gpx parser --- InternalPythonModules/GPX_Module/GPX_Parser_Module.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/InternalPythonModules/GPX_Module/GPX_Parser_Module.py b/InternalPythonModules/GPX_Module/GPX_Parser_Module.py index 0e4face2bc..4d005c74da 100644 --- a/InternalPythonModules/GPX_Module/GPX_Parser_Module.py +++ b/InternalPythonModules/GPX_Module/GPX_Parser_Module.py @@ -236,7 +236,8 @@ class GPXParserFileIngestModule(FileIngestModule): Waypoint(point.latitude, point.longitude, point.elevation, point.name)) try: - geoArtifactHelper.addRoute(None, None, geoWaypoints, None) + if not geoWaypoints.isEmpty(): + geoArtifactHelper.addRoute(None, None, geoWaypoints, None) except Blackboard.BlackboardException as e: self.log("Error posting GPS route artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage()) From 8bac7f3179bdf8acdbba2ea4e16aea17fe504af8 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 1 Jun 2020 08:05:15 -0400 Subject: [PATCH 10/17] fix for gpx parser and add bundle --- .../org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED | 2 ++ InternalPythonModules/GPX_Module/GPX_Parser_Module.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED index f3dab8dd7e..d16fa37761 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED @@ -24,6 +24,8 @@ GeolocationTC_connection_failure_message_title=Connection Failure GeolocationTC_empty_waypoint_message=Unable to generate KML report due to a lack of waypoints.\nPlease make sure there are waypoints visible before generating the KML report GeolocationTC_KML_report_title=KML Report GeolocationTC_report_progress_title=KML Report Progress +GeolocationTopComponent.WaypointFetcher.onErrorDescription=There was an error gathering some GPS Track Data. Some results have been excluded. +GeolocationTopComponent.WaypointFetcher.onErrorTitle=Error gathering GPS Track Data GeoTopComponent_filer_data_invalid_msg=Unable to run waypoint filter.\nPlease select one or more data sources. GeoTopComponent_filer_data_invalid_Title=Filter Failure GeoTopComponent_filter_exception_msg=Exception occurred during waypoint filtering. diff --git a/InternalPythonModules/GPX_Module/GPX_Parser_Module.py b/InternalPythonModules/GPX_Module/GPX_Parser_Module.py index 4d005c74da..3ee603a243 100644 --- a/InternalPythonModules/GPX_Module/GPX_Parser_Module.py +++ b/InternalPythonModules/GPX_Module/GPX_Parser_Module.py @@ -183,7 +183,8 @@ class GPXParserFileIngestModule(FileIngestModule): point.latitude, point.longitude, elevation, None, 0, 0, 0, timeStamp)) try: - geoArtifactHelper.addTrack("Track", geoPointList, None) + if not geoPointList.isEmpty(): + geoArtifactHelper.addTrack("Track", geoPointList, None) except Blackboard.BlackboardException as e: self.log(Level.SEVERE, "Error posting GPS track artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage()) From b830a197a4cc895dd01321d456e6b00b05310a44 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 1 Jun 2020 08:15:03 -0400 Subject: [PATCH 11/17] address codacy remarks --- .../org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java | 3 --- .../autopsy/geolocation/datamodel/WaypointBuilder.java | 2 -- 2 files changed, 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java index 48bff3c69c..f6a4a0b765 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java @@ -22,18 +22,15 @@ package org.sleuthkit.autopsy.geolocation.datamodel; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.logging.Level; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.coreutils.Logger; /** * Class representing a series of waypoints that form a path. */ public class GeoPath { - private static final Logger LOGGER = Logger.getLogger(GeoPath.class.getName()); private final List waypointList; private final String pathName; private final BlackboardArtifact artifact; diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java index 2188af8e48..40c1092928 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java @@ -26,8 +26,6 @@ import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; -import org.apache.commons.lang3.tuple.Pair; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; From bbbd5d87b5aecc3b7a0e55f124c770689ccb83ce Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 1 Jun 2020 15:06:13 -0400 Subject: [PATCH 12/17] added key accelerators --- .../autopsy/imagegallery/actions/CategorizeAction.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 6eaddeef9d..0af5965b16 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -82,6 +82,12 @@ public class CategorizeAction extends Action { this.tagName = tagName; setGraphic(getGraphic(tagName)); setEventHandler(actionEvent -> addCatToFiles(selectedFileIDs)); + + int rank = tagName.getRank(); + // Only map to a key if the rank is less than 10 + if(rank < 10) { + setAccelerator(new KeyCodeCombination(KeyCode.getKeyCode(Integer.toString(rank)))); + } } static public Menu getCategoriesMenu(ImageGalleryController controller) { From 9301c9239c32161711e1520a8be27beb689642b6 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 1 Jun 2020 15:38:22 -0400 Subject: [PATCH 13/17] Put Tag nodes into alphebetical order --- Core/src/org/sleuthkit/autopsy/datamodel/Tags.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 659ee84870..871f7ba07b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Collections; +import java.util.Comparator; import java.util.EnumSet; import java.util.List; import java.util.Observable; @@ -31,6 +32,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; @@ -43,6 +45,7 @@ import org.sleuthkit.autopsy.tags.TagUtils; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TagSet; import org.sleuthkit.datamodel.TskCoreException; /** @@ -252,7 +255,12 @@ public class Tags implements AutopsyVisitableItem { ? Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(filteringDSObjId) : Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(); } - Collections.sort(tagNamesInUse); + Collections.sort(tagNamesInUse, new Comparator() { + @Override + public int compare(TagName o1, TagName o2) { + return TagUtils.getDecoratedTagDisplayName(o1).compareTo(TagUtils.getDecoratedTagDisplayName(o2)); + } + }); keys.addAll(tagNamesInUse); } catch (TskCoreException | NoCurrentCaseException ex) { Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS From 1ade5a4f344741007b1c72cb5247b8c04a5cbaf6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 2 Jun 2020 08:39:27 -0400 Subject: [PATCH 14/17] updates based on comments --- .../geolocation/AbstractWaypointFetcher.java | 27 ++-- .../geolocation/GeolocationTopComponent.java | 5 +- .../datamodel/GeoLocationParseResult.java | 149 ++++-------------- .../geolocation/datamodel/GeoPath.java | 13 +- .../datamodel/WaypointBuilder.java | 52 +++--- .../autopsy/report/modules/kml/KMLReport.java | 20 ++- 6 files changed, 93 insertions(+), 173 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java index eb0371bdae..fccdfacd29 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/AbstractWaypointFetcher.java @@ -27,7 +27,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult; -import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult.SeparationResult; import org.sleuthkit.autopsy.geolocation.datamodel.Track; import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint; import org.sleuthkit.autopsy.geolocation.datamodel.WaypointBuilder; @@ -72,18 +71,21 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter } + /** * Called after all of the MapWaypoints are created from all of the * TSK_GPS_XXX objects. - * + * * @param mapWaypoints List of filtered MapWaypoints. + * @param tracks The tracks that were successfully parsed. + * @param wasEntirelySuccessful True if no errors occurred while processing. */ abstract void handleFilteredWaypointSet(Set mapWaypoints, List> tracks, - List> failedTracks, List> failedWaypoints); + boolean wasEntirelySuccessful); @Override - public void process(List> waypointResults) { - List> trackResults = new ArrayList<>(); + public void process(GeoLocationParseResult waypointResults) { + GeoLocationParseResult trackResults = null; if (filters.getArtifactTypes().contains(ARTIFACT_TYPE.TSK_GPS_TRACK)) { try { trackResults = Track.getTracks(Case.getCurrentCase().getSleuthkitCase(), filters.getDataSources()); @@ -91,12 +93,11 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter logger.log(Level.WARNING, "Exception thrown while retrieving list of Tracks", ex); } } - - SeparationResult separatedWaypoints = GeoLocationParseResult.separate(waypointResults); - SeparationResult separatedTracks = GeoLocationParseResult.separate(trackResults); - - Pair, List>> waypointsAndTracks = - createWaypointList(separatedWaypoints.getParsedItems(), separatedTracks.getParsedItems()); + + Pair, List>> waypointsAndTracks = createWaypointList( + waypointResults.getItems(), + (trackResults == null) ? new ArrayList() : trackResults.getItems()); + final Set pointSet = MapWaypoint.getWaypoints(waypointsAndTracks.getKey()); final List> trackSets = new ArrayList<>(); @@ -104,7 +105,9 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter trackSets.add(MapWaypoint.getWaypoints(t)); } - handleFilteredWaypointSet(pointSet, trackSets, separatedTracks.getFailedItems(), separatedWaypoints.getFailedItems()); + handleFilteredWaypointSet( + pointSet, trackSets, + (trackResults == null || trackResults.isSuccessfullyParsed()) && waypointResults.isSuccessfullyParsed()); } /** diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java index d7da9c0df4..38523c1a9d 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java @@ -508,12 +508,11 @@ public final class GeolocationTopComponent extends TopComponent { } @Override - void handleFilteredWaypointSet(Set mapWaypoints, List> tracks, - List> failedTracks, List> failedWaypoints) { + void handleFilteredWaypointSet(Set mapWaypoints, List> tracks, boolean wasEntirelySuccessful) { addWaypointsToMap(mapWaypoints, tracks); // if there is an error, present to the user. - if ((failedTracks != null && !failedTracks.isEmpty()) || (failedWaypoints != null && !failedWaypoints.isEmpty())) { + if (!wasEntirelySuccessful) { JOptionPane.showMessageDialog(GeolocationTopComponent.this, Bundle.GeolocationTopComponent_WaypointFetcher_onErrorDescription(), Bundle.GeolocationTopComponent_WaypointFetcher_onErrorTitle(), diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java index 67438b7275..db5502541d 100644 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java @@ -20,118 +20,56 @@ package org.sleuthkit.autopsy.geolocation.datamodel; import java.util.ArrayList; import java.util.List; -import org.apache.commons.collections4.ListUtils; -import org.sleuthkit.datamodel.BlackboardArtifact; +import org.python.google.common.collect.ImmutableList; /** * The result of attempting to parse a GeoLocation object. */ public class GeoLocationParseResult { - private final boolean successfullyParsed; - private final GeoLocationDataException exception; - private final BlackboardArtifact artifact; - private final T geoObject; + private boolean successfullyParsed; + private List items = new ArrayList<>(); - GeoLocationParseResult(BlackboardArtifact artifact, - boolean successfullyParsed, GeoLocationDataException exception, T geoObject) { + /** + * Returns a GeoLocationParseResult with no items and declared successfully + * parsed. + */ + public GeoLocationParseResult() { + successfullyParsed = true; + } + /** + * Returns a new GeoLocationParseResult. + * + * @param items The items to copy to this result (can be null). + * @param successfullyParsed Whether or not the operation was entirely + * successful. + */ + public GeoLocationParseResult(List items, boolean successfullyParsed) { this.successfullyParsed = successfullyParsed; - this.exception = exception; - this.artifact = artifact; - this.geoObject = geoObject; + + if (items != null) { + this.items.addAll(items); + } } /** - * Creates a GeoLocationParseResult as the result of a successful parse. - * @param The type of object to parse. - * @param artifact The artifact that was parsed or failed in parsing - * (could be null). - * @param geoObject The GeoLocation object to include in result. + * Adds the content of the GeoLocationParseResult parameter to this. Items + * will be concatenated and this object's successfullyParsed status will be + * true if it is already true and the object is true as well. * - * @return The generated WaypointParseResult. + * @param toAdd The GeoLocationParseResult to add. */ - public static GeoLocationParseResult create(BlackboardArtifact artifact, T geoObject) { - if (geoObject == null) { - return new GeoLocationParseResult(artifact, false, new GeoLocationDataException("GeoLocation object provided was null"), null); - } + public void add(GeoLocationParseResult toAdd) { + this.successfullyParsed = (this.successfullyParsed == false) + ? false + : toAdd.isSuccessfullyParsed(); - return new GeoLocationParseResult(artifact, true, null, geoObject); + this.items.addAll(toAdd.getItems()); } /** - * Creates a GeoLocationParseResult indicating a failed parsing. - * - * @param The type of GeoLocation object that was supposed to - * be parsed. - * @param artifact The artifact that was parsed or failed in parsing - * (could be null). - * @param exception The exception generated. - * - * @return The GeoLocationParseResult indicating an error. - */ - public static GeoLocationParseResult error(BlackboardArtifact artifact, GeoLocationDataException exception) { - return new GeoLocationParseResult(artifact, false, exception, null); - } - - /** - * The result of splitting an iterable of GeoLocationParseResults into a - * list of successfully parsed items and a list of failures. - * - * @param The parsed item type. - */ - public static class SeparationResult { - - private final List> failedItems; - private final List parsedItems; - - SeparationResult(List> failedItems, List parsedItems) { - this.failedItems = failedItems; - this.parsedItems = parsedItems; - } - - /** - * @return The items that failed to parse properly. - */ - public List> getFailedItems() { - return failedItems; - } - - /** - * @return The underlying items that were successfully parsed. - */ - public List getParsedItems() { - return parsedItems; - } - } - - /** - * Separates an iterable of GeoLocationParseResult objects into failed items - * and successfully parsed items. - * - * @param The underlying type that was parsed. - * @param items The items to separate. - * - * @return The SeparationResult with successfully parsed and failed items. - */ - public static SeparationResult separate(Iterable> items) { - List> failedItems = new ArrayList<>(); - List parsedItems = new ArrayList<>(); - for (GeoLocationParseResult item : items) { - if (item.isSuccessfullyParsed()) { - parsedItems.add(item.getGeoLocationObject()); - } else { - failedItems.add(item); - } - } - - return new SeparationResult(ListUtils.unmodifiableList(failedItems), ListUtils.unmodifiableList(parsedItems)); - } - - /** - * Whether or not the GeoLocation object has been successfully parsed. If - * true, there should be a non-null GeoLocation object present. Otherwise, - * there should be a non-null exception. + * Whether or not the GeoLocation object has been successfully parsed. * * @return Whether or not the GeoLocation object has been successfully * parsed. @@ -141,26 +79,9 @@ public class GeoLocationParseResult { } /** - * @return The exception caused in attempting to parse the GeoLocation - * object if there was an exception. + * @return The successfully parsed GeoLocation objects. */ - public GeoLocationDataException getException() { - return exception; - } - - /** - * @return The parsed GeoLocation object if the waypoint was successfully - * parsed. - */ - public T getGeoLocationObject() { - return geoObject; - } - - /** - * @return The artifact that was parsed or failed in parsing (could be - * null). - */ - public BlackboardArtifact getArtifact() { - return artifact; + public List getItems() { + return ImmutableList.copyOf(items); } } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java index f6a4a0b765..a1d369808a 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoPath.java @@ -73,25 +73,26 @@ public class GeoPath { * * @throws GeoLocationDataException */ - public static List> getTracks(SleuthkitCase skCase, List sourceList) throws GeoLocationDataException { + public static GeoLocationParseResult getTracks(SleuthkitCase skCase, List sourceList) throws GeoLocationDataException { List artifacts = null; - List> tracks = new ArrayList<>(); + boolean allParsedSuccessfully = true; + List tracks = new ArrayList<>(); try { artifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACK); for (BlackboardArtifact artifact : artifacts) { if (sourceList == null || sourceList.contains(artifact.getDataSource())) { try { - Track route = new Track(artifact); - tracks.add(GeoLocationParseResult.create(artifact,route)); + tracks.add(new Track(artifact)); + } catch (GeoLocationDataException e) { - tracks.add(GeoLocationParseResult.error(artifact, e)); + allParsedSuccessfully = false; } } } } catch (TskCoreException ex) { throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_BOOKMARK", ex); } - return tracks; + return new GeoLocationParseResult(tracks, allParsedSuccessfully); } /** diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java index 9ae1ce9b3d..9f86cb2065 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java @@ -98,9 +98,10 @@ public final class WaypointBuilder { /** * This function will be called after the waypoints have been filtered. * - * @param waypoints The list of waypoints. + * @param waypoints The list of waypoints and whether they were all + * successfully parsed. */ - void process(List> waypoints); + void process(GeoLocationParseResult waypoints); } /** @@ -480,7 +481,7 @@ public final class WaypointBuilder { skCase.getCaseDbAccessManager().select(query, new CaseDbAccessManager.CaseDbAccessQueryCallback() { @Override public void process(ResultSet rs) { - List> waypointResults = new ArrayList<>(); + GeoLocationParseResult waypointResults = new GeoLocationParseResult<>(); try { while (rs.next()) { int artifact_type_id = rs.getInt("artifact_type_id"); //NON-NLS @@ -488,7 +489,7 @@ public final class WaypointBuilder { ARTIFACT_TYPE type = ARTIFACT_TYPE.fromID(artifact_type_id); if (artifactTypes.contains(type)) { - waypointResults.addAll(getWaypointForArtifact(skCase.getBlackboardArtifact(artifact_id), type)); + waypointResults.add(getWaypointForArtifact(skCase.getBlackboardArtifact(artifact_id), type)); } } @@ -636,7 +637,7 @@ public final class WaypointBuilder { /** * Parses one waypoint. * - * @param parser The parser to use. + * @param parser The parser to use. * @param artifact The artifact to be parsed. * * @return Returns a parse result that is either successful with a parsed @@ -644,29 +645,26 @@ public final class WaypointBuilder { */ private static GeoLocationParseResult parseWaypoint(ParserWithError parser, BlackboardArtifact artifact) { try { - return GeoLocationParseResult.create(artifact, parser.parse(artifact)); + return new GeoLocationParseResult<>(Arrays.asList(parser.parse(artifact)), true); } catch (GeoLocationDataException ex) { - return GeoLocationParseResult.error(artifact, ex); + return new GeoLocationParseResult<>(null, false); } } /** * Parses a list of waypoints. * - * @param parser The parser to use. + * @param parser The parser to use. * @param artifact The artifact to be parsed. * - * @return Returns a list of parse results with the successfully parsed - * items or a list with one item indicating the failure. + * @return Returns a parse result that is either successful with a parsed + * waypoint or unsuccessful with an exception. */ - private static List> parseWaypoints(ParserWithError> parser, BlackboardArtifact artifact) { + private static GeoLocationParseResult parseWaypoints(ParserWithError> parser, BlackboardArtifact artifact) { try { - return parser.parse(artifact).stream() - .map((result) -> GeoLocationParseResult.create(artifact, result)) - .collect(Collectors.toList()); - - } catch (GeoLocationDataException ex) { - return Arrays.asList(GeoLocationParseResult.error(artifact, ex)); + return new GeoLocationParseResult<>(parser.parse(artifact), true); + } catch (GeoLocationDataException ignored) { + return new GeoLocationParseResult<>(null, false); } } @@ -678,32 +676,32 @@ public final class WaypointBuilder { * * @return A new waypoint object */ - private static List> getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type) { - List> waypoints = new ArrayList<>(); + private static GeoLocationParseResult getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type) { + GeoLocationParseResult waypoints = new GeoLocationParseResult<>(); switch (type) { case TSK_METADATA_EXIF: - waypoints.add(parseWaypoint((a) -> new EXIFWaypoint(a), artifact)); + waypoints.add(parseWaypoint(EXIFWaypoint::new, artifact)); break; case TSK_GPS_BOOKMARK: - waypoints.add(parseWaypoint((a) -> new BookmarkWaypoint(a), artifact)); + waypoints.add(parseWaypoint(BookmarkWaypoint::new, artifact)); break; case TSK_GPS_TRACKPOINT: - waypoints.add(parseWaypoint((a) -> new TrackpointWaypoint(a), artifact)); + waypoints.add(parseWaypoint(TrackpointWaypoint::new, artifact)); break; case TSK_GPS_SEARCH: - waypoints.add(parseWaypoint((a) -> new SearchWaypoint(a), artifact)); + waypoints.add(parseWaypoint(SearchWaypoint::new, artifact)); break; case TSK_GPS_ROUTE: - waypoints.addAll(parseWaypoints((a) -> new Route(a).getRoute(), artifact)); + waypoints.add(parseWaypoints((a) -> new Route(a).getRoute(), artifact)); break; case TSK_GPS_LAST_KNOWN_LOCATION: - waypoints.add(parseWaypoint((a) -> new LastKnownWaypoint(a), artifact)); + waypoints.add(parseWaypoint(LastKnownWaypoint::new, artifact)); break; case TSK_GPS_TRACK: - waypoints.addAll(parseWaypoints((a) -> new Track(a).getPath(), artifact)); + waypoints.add(parseWaypoints((a) -> new Track(a).getPath(), artifact)); break; default: - waypoints.add(parseWaypoint((a) -> new CustomArtifactWaypoint(a), artifact)); + waypoints.add(parseWaypoint(CustomArtifactWaypoint::new, artifact)); } return waypoints; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java index a4d67313eb..c9e70cb185 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java @@ -48,7 +48,6 @@ import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult; -import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult.SeparationResult; import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint; import org.sleuthkit.autopsy.geolocation.datamodel.Route; import org.sleuthkit.autopsy.geolocation.datamodel.Track; @@ -213,8 +212,8 @@ public final class KMLReport implements GeneralReportModule { try { makeRoutes(skCase); - List> errors = makeTracks(skCase); - if (!errors.isEmpty()) { + boolean entirelySuccessful = makeTracks(skCase); + if (!entirelySuccessful) { result = ReportProgressPanel.ReportStatus.ERROR; errorMessage = Bundle.KMLReport_partialFailure(); } @@ -525,21 +524,20 @@ public final class KMLReport implements GeneralReportModule { * Add the track to the track folder in the document. * * @param skCase Currently open case. - * @return The items that could not be parsed appropriately. + * @return The operation was entirely successful. * * @throws TskCoreException */ - List> makeTracks(SleuthkitCase skCase) throws GeoLocationDataException, TskCoreException { + boolean makeTracks(SleuthkitCase skCase) throws GeoLocationDataException, TskCoreException { List tracks = null; - List> failedItems; + boolean successful = true; if (waypointList == null) { - SeparationResult result = GeoLocationParseResult.separate(Track.getTracks(skCase, null)); - tracks = result.getParsedItems(); - failedItems = result.getFailedItems(); + GeoLocationParseResult result = Track.getTracks(skCase, null); + tracks = result.getItems(); + successful = result.isSuccessfullyParsed(); } else { tracks = WaypointBuilder.getTracks(waypointList); - failedItems = new ArrayList<>(); } for (Track track : tracks) { @@ -549,7 +547,7 @@ public final class KMLReport implements GeneralReportModule { addTrackToReport(track); } - return failedItems; + return successful; } /** From 481318bde4a4597e2e4f333f13f636eded599203 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 2 Jun 2020 09:48:03 -0400 Subject: [PATCH 15/17] Removed unused imports --- Core/src/org/sleuthkit/autopsy/datamodel/Tags.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 871f7ba07b..6fa6487b5e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -32,7 +32,6 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; @@ -45,7 +44,6 @@ import org.sleuthkit.autopsy.tags.TagUtils; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TagSet; import org.sleuthkit.datamodel.TskCoreException; /** @@ -258,7 +256,7 @@ public class Tags implements AutopsyVisitableItem { Collections.sort(tagNamesInUse, new Comparator() { @Override public int compare(TagName o1, TagName o2) { - return TagUtils.getDecoratedTagDisplayName(o1).compareTo(TagUtils.getDecoratedTagDisplayName(o2)); + return TagUtils.getDecoratedTagDisplayName(o1).compareTo(TagUtils.getDecoratedTagDisplayName(o2)); } }); keys.addAll(tagNamesInUse); From fc01fcd48d095c7bd71d50be34d10ff8e042e63d Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 2 Jun 2020 11:58:35 -0400 Subject: [PATCH 16/17] fix for codacy and commenting issues --- .../autopsy/geolocation/GeolocationTopComponent.java | 3 --- .../geolocation/datamodel/GeoLocationParseResult.java | 9 +++------ .../autopsy/geolocation/datamodel/WaypointBuilder.java | 1 - .../sleuthkit/autopsy/report/modules/kml/KMLReport.java | 1 - 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java index 38523c1a9d..31ef953fdc 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeolocationTopComponent.java @@ -50,9 +50,6 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.geolocation.GeoFilterPanel.GeoFilter; import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException; -import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationParseResult; -import org.sleuthkit.autopsy.geolocation.datamodel.Track; -import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint; import org.sleuthkit.autopsy.ingest.IngestManager; import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java index db5502541d..2089bc2cb6 100644 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/GeoLocationParseResult.java @@ -23,12 +23,12 @@ import java.util.List; import org.python.google.common.collect.ImmutableList; /** - * The result of attempting to parse a GeoLocation object. + * The result of attempting to parse GeoLocation objects. */ public class GeoLocationParseResult { private boolean successfullyParsed; - private List items = new ArrayList<>(); + private final List items = new ArrayList<>(); /** * Returns a GeoLocationParseResult with no items and declared successfully @@ -61,10 +61,7 @@ public class GeoLocationParseResult { * @param toAdd The GeoLocationParseResult to add. */ public void add(GeoLocationParseResult toAdd) { - this.successfullyParsed = (this.successfullyParsed == false) - ? false - : toAdd.isSuccessfullyParsed(); - + this.successfullyParsed = this.successfullyParsed && toAdd.isSuccessfullyParsed(); this.items.addAll(toAdd.getItems()); } diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java index 9f86cb2065..076ac8b8f9 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/WaypointBuilder.java @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Level; -import java.util.stream.Collectors; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java index c9e70cb185..607b8879fe 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/kml/KMLReport.java @@ -33,7 +33,6 @@ import java.io.OutputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; From 119aef5f75c9b9c5740bc3c9d9cd8a422504447b Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 2 Jun 2020 13:22:26 -0400 Subject: [PATCH 17/17] Added hotkey value to menu item --- .../autopsy/imagegallery/gui/GuiUtils.java | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java index 4699046655..7e528c4186 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java @@ -21,12 +21,19 @@ package org.sleuthkit.autopsy.imagegallery.gui; import java.io.IOException; import java.net.URL; import java.util.logging.Level; +import javafx.geometry.HPos; +import javafx.geometry.Pos; import javafx.scene.control.ButtonBase; import javafx.scene.control.CustomMenuItem; import javafx.scene.control.Dialog; import javafx.scene.control.Label; import javafx.scene.control.MenuItem; import javafx.scene.image.Image; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; import javafx.stage.Stage; import org.controlsfx.control.action.Action; import org.controlsfx.control.action.ActionUtils; @@ -67,7 +74,31 @@ public final class GuiUtils { * @return */ public static MenuItem createAutoAssigningMenuItem(ButtonBase button, Action action) { - MenuItem menuItem = new CustomMenuItem(new Label(action.getText(), action.getGraphic())); + Label mainLabel = new Label(action.getText(), action.getGraphic()); + + String hkDisplayText = action.getAccelerator() != null ? action.getAccelerator().getDisplayText() : ""; + Label hotKeyLabel = new Label(hkDisplayText); + + hotKeyLabel.setMaxWidth(100); + + GridPane grid = new GridPane(); + grid.setAlignment(Pos.CENTER); + grid.setHgap(10); + + ColumnConstraints column1 = new ColumnConstraints(); + column1.setHalignment(HPos.LEFT); + grid.getColumnConstraints().add(column1); + + ColumnConstraints column2 = new ColumnConstraints(); + column2.setHalignment(HPos.RIGHT); + column2.setMaxWidth(Double.MAX_VALUE); + grid.getColumnConstraints().add(column2); + + grid.add(mainLabel, 0, 0); + grid.add(hotKeyLabel, 1, 0); + grid.setMaxWidth(Double.MAX_VALUE); + + MenuItem menuItem = new CustomMenuItem(grid); ActionUtils.configureMenuItem(action, menuItem); menuItem.setOnAction(actionEvent -> { action.handle(actionEvent);