Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
WaypointBuilder.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2019 Basis Technology Corp.
6  * contact: carrier <at> sleuthkit <dot> org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 package org.sleuthkit.autopsy.geolocation.datamodel;
21 
22 import java.sql.ResultSet;
23 import java.sql.SQLException;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.logging.Level;
29 import org.sleuthkit.datamodel.BlackboardArtifact;
30 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
31 import org.sleuthkit.datamodel.CaseDbAccessManager;
32 import org.sleuthkit.datamodel.BlackboardAttribute;
33 import org.sleuthkit.datamodel.SleuthkitCase;
34 import org.sleuthkit.datamodel.TskCoreException;
35 import org.sleuthkit.datamodel.DataSource;
36 
41 public final class WaypointBuilder {
42 
43  private static final Logger logger = Logger.getLogger(WaypointBuilder.class.getName());
44 
45  private final static String TIME_TYPE_IDS = String.format("%d, %d",
46  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(),
47  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID());
48 
49  private final static String GEO_ATTRIBUTE_TYPE_IDS = String.format("%d, %d, %d",
50  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(),
51  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START.getTypeID(),
52  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_WAYPOINTS.getTypeID());
53 
54  // SELECT statement for getting a list of waypoints where %s is a comma separated list
55  // of attribute type ids.
56  private final static String GEO_ARTIFACT_QUERY
57  = "SELECT artifact_id, artifact_type_id "
58  + "FROM blackboard_attributes "
59  + "WHERE attribute_type_id IN (%s) "; //NON-NLS
60 
61  // SELECT statement to get only artifact_ids
62  private final static String GEO_ARTIFACT_QUERY_ID_ONLY
63  = "SELECT artifact_id "
64  + "FROM blackboard_attributes "
65  + "WHERE attribute_type_id IN (%s) "; //NON-NLS
66 
67  // This Query will return a list of waypoint artifacts
68  private final static String GEO_ARTIFACT_WITH_DATA_SOURCES_QUERY
69  = "SELECT blackboard_attributes.artifact_id "
70  + "FROM blackboard_attributes, blackboard_artifacts "
71  + "WHERE blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id "
72  + "AND blackboard_attributes.attribute_type_id IN(%s) "
73  + "AND data_source_obj_id IN (%s)"; //NON-NLS
74 
75  // Select will return the "most recent" timestamp from all waypoings
76  private final static String MOST_RECENT_TIME
77  = "SELECT MAX(value_int64) - (%d * 86400)" //86400 is the number of seconds in a day.
78  + "FROM blackboard_attributes "
79  + "WHERE attribute_type_id IN(%s) "
80  + "AND artifact_id "
81  + "IN ( "
82  + "%s" //GEO_ARTIFACT with or without data source
83  + " )";
84 
85  // Returns a list of artifacts with no time stamp
86  private final static String SELECT_WO_TIMESTAMP
87  = "SELECT DISTINCT artifact_id, artifact_type_id "
88  + "FROM blackboard_attributes "
89  + "WHERE artifact_id NOT IN (%s) "
90  + "AND artifact_id IN (%s)"; //NON-NLS
91 
95  public interface WaypointFilterQueryCallBack {
96 
104  }
105 
109  private WaypointBuilder() {
110 
111  }
112 
126  public static List<Waypoint> getAllWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
127  List<Waypoint> points = new ArrayList<>();
128 
129  points.addAll(getTrackpointWaypoints(skCase));
130  points.addAll(getEXIFWaypoints(skCase));
131  points.addAll(getSearchWaypoints(skCase));
132  points.addAll(getLastKnownWaypoints(skCase));
133  points.addAll(getBookmarkWaypoints(skCase));
134 
135  return points;
136  }
137 
145  public static List<Route> getRoutes(List<Waypoint> waypoints) {
146  List<Route> routeList = new ArrayList<>();
147  for (Waypoint point : waypoints) {
148  GeoPath path = point.getParentGeoPath();
149  if (path instanceof Route) {
150  Route route = (Route) path;
151  if (!routeList.contains(route)) {
152  routeList.add(route);
153  }
154  }
155  }
156 
157  return routeList;
158  }
159 
167  public static List<Track> getTracks(List<Waypoint> waypoints) {
168  List<Track> trackList = new ArrayList<>();
169  for (Waypoint point : waypoints) {
170  GeoPath path = point.getParentGeoPath();
171  if (path instanceof Track) {
172  Track route = (Track) path;
173  if (!trackList.contains(route)) {
174  trackList.add(route);
175  }
176  }
177  }
178 
179  return trackList;
180  }
181 
189  public static List<Area> getAreas(List<Waypoint> waypoints) {
190  List<Area> areaList = new ArrayList<>();
191  for (Waypoint point : waypoints) {
192  GeoPath path = point.getParentGeoPath();
193  if (path instanceof Area) {
194  Area area = (Area) path;
195  if (!areaList.contains(area)) {
196  areaList.add(area);
197  }
198  }
199  }
200 
201  return areaList;
202  }
203 
213  @SuppressWarnings("deprecation")
214  public static List<Waypoint> getTrackpointWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
215  List<BlackboardArtifact> artifacts = null;
216  try {
217  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_GPS_TRACKPOINT);
218  } catch (TskCoreException ex) {
219  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_TRACKPOINT", ex);//NON-NLS
220  }
221 
222  List<Waypoint> points = new ArrayList<>();
223  for (BlackboardArtifact artifact : artifacts) {
224  try {
225  Waypoint point = new TrackpointWaypoint(artifact);
226  points.add(point);
227  } catch (GeoLocationDataException ex) {
228  logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_TRACKPOINT artifactID: %d", artifact.getArtifactID()));//NON-NLS
229  }
230  }
231  return points;
232  }
233 
241  public static List<Waypoint> getTrackpointWaypoints(List<Waypoint> waypoints) {
242  List<Waypoint> specificPoints = new ArrayList<>();
243 
244  for (Waypoint point : waypoints) {
245  if (point instanceof TrackpointWaypoint) {
246  specificPoints.add(point);
247  }
248  }
249 
250  return specificPoints;
251  }
252 
262  static public List<Waypoint> getEXIFWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
263  List<BlackboardArtifact> artifacts = null;
264  try {
265  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_METADATA_EXIF);
266  } catch (TskCoreException ex) {
267  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_LAST_KNOWN_LOCATION", ex);//NON-NLS
268  }
269 
270  List<Waypoint> points = new ArrayList<>();
271  if (artifacts != null) {
272  for (BlackboardArtifact artifact : artifacts) {
273  try {
274  Waypoint point = new EXIFWaypoint(artifact);
275  points.add(point);
276  } catch (GeoLocationDataException ex) {
277  // I am a little relucant to log this error because I suspect
278  // this will happen more often than not. It is valid for
279  // METADAT_EXIF to not have longitude and latitude
280  }
281  }
282  }
283  return points;
284  }
285 
293  public static List<Waypoint> getEXIFWaypoints(List<Waypoint> waypoints) {
294  List<Waypoint> specificPoints = new ArrayList<>();
295 
296  for (Waypoint point : waypoints) {
297  if (point instanceof EXIFWaypoint) {
298  specificPoints.add(point);
299  }
300  }
301 
302  return specificPoints;
303  }
304 
314  public static List<Waypoint> getSearchWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
315  List<BlackboardArtifact> artifacts = null;
316  try {
317  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_GPS_SEARCH);
318  } catch (TskCoreException ex) {
319  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_SEARCH", ex);//NON-NLS
320  }
321 
322  List<Waypoint> points = new ArrayList<>();
323  if (artifacts != null) {
324  for (BlackboardArtifact artifact : artifacts) {
325  try {
326  Waypoint point = new SearchWaypoint(artifact);
327  points.add(point);
328  } catch (GeoLocationDataException ex) {
329  logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_SEARCH artifactID: %d", artifact.getArtifactID()));//NON-NLS
330  }
331  }
332  }
333  return points;
334  }
335 
343  public static List<Waypoint> getSearchWaypoints(List<Waypoint> waypoints) {
344  List<Waypoint> specificPoints = new ArrayList<>();
345 
346  for (Waypoint point : waypoints) {
347  if (point instanceof SearchWaypoint) {
348  specificPoints.add(point);
349  }
350  }
351 
352  return specificPoints;
353  }
354 
364  public static List<Waypoint> getLastKnownWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
365  List<BlackboardArtifact> artifacts = null;
366  try {
367  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION);
368  } catch (TskCoreException ex) {
369  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_LAST_KNOWN_LOCATION", ex);//NON-NLS
370  }
371 
372  List<Waypoint> points = new ArrayList<>();
373  if (artifacts != null) {
374  for (BlackboardArtifact artifact : artifacts) {
375  try {
376  Waypoint point = new LastKnownWaypoint(artifact);
377  points.add(point);
378  } catch (GeoLocationDataException ex) {
379  logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_LAST_KNOWN_LOCATION artifactID: %d", artifact.getArtifactID()));//NON-NLS
380  }
381  }
382  }
383  return points;
384  }
385 
394  public static List<Waypoint> getLastKnownWaypoints(List<Waypoint> waypoints) {
395  List<Waypoint> specificPoints = new ArrayList<>();
396 
397  for (Waypoint point : waypoints) {
398  if (point instanceof LastKnownWaypoint) {
399  specificPoints.add(point);
400  }
401  }
402 
403  return specificPoints;
404  }
405 
415  public static List<Waypoint> getBookmarkWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
416  List<BlackboardArtifact> artifacts = null;
417  try {
418  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_GPS_BOOKMARK);
419  } catch (TskCoreException ex) {
420  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_BOOKMARK", ex);//NON-NLS
421  }
422 
423  List<Waypoint> points = new ArrayList<>();
424  if (artifacts != null) {
425  for (BlackboardArtifact artifact : artifacts) {
426  try {
427  Waypoint point = new BookmarkWaypoint(artifact);
428  points.add(point);
429  } catch (GeoLocationDataException ex) {
430  logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_BOOKMARK artifactID: %d", artifact.getArtifactID()), ex);//NON-NLS
431  }
432  }
433  }
434  return points;
435  }
436 
445  public static List<Waypoint> getBookmarkWaypoints(List<Waypoint> waypoints) {
446  List<Waypoint> specificPoints = new ArrayList<>();
447 
448  for (Waypoint point : waypoints) {
449  if (point instanceof BookmarkWaypoint) {
450  specificPoints.add(point);
451  }
452  }
453 
454  return specificPoints;
455  }
456 
490  static public void getAllWaypoints(SleuthkitCase skCase, List<DataSource> dataSources, List<ARTIFACT_TYPE> artifactTypes, boolean showAll, int cntDaysFromRecent, boolean noTimeStamp, WaypointFilterQueryCallBack queryCallBack) throws GeoLocationDataException {
491  String query = buildQuery(dataSources, showAll, cntDaysFromRecent, noTimeStamp);
492 
493  try {
494  // The CaseDBAccessManager.select function will add a SELECT
495  // to the beginning of the query
496  if (query.startsWith("SELECT")) { //NON-NLS
497  query = query.replaceFirst("SELECT", ""); //NON-NLS
498  }
499 
500  skCase.getCaseDbAccessManager().select(query, new CaseDbAccessManager.CaseDbAccessQueryCallback() {
501  @Override
502  public void process(ResultSet rs) {
504  try {
505  while (rs.next()) {
506  int artifact_type_id = rs.getInt("artifact_type_id"); //NON-NLS
507  long artifact_id = rs.getLong("artifact_id"); //NON-NLS
508 
509  ARTIFACT_TYPE type = ARTIFACT_TYPE.fromID(artifact_type_id);
510  if (artifactTypes.contains(type)) {
511  waypointResults.add(getWaypointForArtifact(skCase.getBlackboardArtifact(artifact_id), type));
512  }
513 
514  }
515 
516  queryCallBack.process(waypointResults);
517  } catch (SQLException | TskCoreException ex) {
518  logger.log(Level.WARNING, "Failed to filter waypoint.", ex); //NON-NLS
519  }
520 
521  }
522  });
523  } catch (TskCoreException ex) {
524  logger.log(Level.WARNING, "Failed to filter waypoint.", ex); //NON-NLS
525  }
526  }
527 
536  static private String buildQueryForWaypointsWOTimeStamps(List<DataSource> dataSources) {
537 
538 // SELECT_WO_TIMESTAMP
539 // SELECT DISTINCT artifact_id, artifact_type_id
540 // FROM blackboard_attributes
541 // WHERE artifact_id NOT IN (%s)
542 // AND artifact_id IN (%s)
543 // GEO_ARTIFACT_QUERY_ID_ONLY
544 // SELECT artifact_id
545 // FROM blackboard_attributes
546 // WHERE attribute_type_id IN (%d, %d)
547  return String.format(SELECT_WO_TIMESTAMP,
548  String.format(GEO_ARTIFACT_QUERY_ID_ONLY, TIME_TYPE_IDS),
549  getWaypointListQuery(dataSources));
550  }
551 
574  static private String buildQuery(List<DataSource> dataSources, boolean showAll, int cntDaysFromRecent, boolean noTimeStamp) {
575  String mostRecentQuery = "";
576 
577  if (!showAll && cntDaysFromRecent > 0) {
578 // MOST_RECENT_TIME
579 // SELECT MAX(value_int64) - (%d * 86400)
580 // FROM blackboard_attributes
581 // WHERE attribute_type_id IN(%s)
582 // AND artifact_id
583 // IN ( %s )
584 //
585  mostRecentQuery = String.format("AND value_int64 > (%s)", //NON-NLS
586  String.format(MOST_RECENT_TIME,
587  cntDaysFromRecent, TIME_TYPE_IDS,
588  getWaypointListQuery(dataSources)
589  ));
590  }
591 
592 // GEO_ARTIFACT_QUERY
593 // SELECT artifact_id, artifact_type_id
594 // FROM blackboard_attributes
595 // WHERE attribute_type_id IN (%s)
596  String query = String.format(GEO_ARTIFACT_QUERY, TIME_TYPE_IDS);
597 
598  // That are in the list of artifacts for the given data Sources
599  query += String.format("AND artifact_id IN(%s)", getWaypointListQuery(dataSources)); //NON-NLS
600  query += mostRecentQuery;
601 
602  if (showAll || noTimeStamp) {
603  query = String.format("%s UNION %s", buildQueryForWaypointsWOTimeStamps(dataSources), query); //NON-NLS
604  }
605 
606  return query;
607  }
608 
621  static private String getWaypointListQuery(List<DataSource> dataSources) {
622 
623  if (dataSources == null || dataSources.isEmpty()) {
624 // GEO_ARTIFACT_QUERY
625 // SELECT artifact_id, artifact_type_id
626 // FROM blackboard_attributes
627 // WHERE attribute_type_id IN (%s)
628  return String.format(GEO_ARTIFACT_QUERY, GEO_ATTRIBUTE_TYPE_IDS);
629  }
630 
631  String dataSourceList = "";
632  for (DataSource source : dataSources) {
633  dataSourceList += Long.toString(source.getId()) + ",";
634  }
635 
636  if (!dataSourceList.isEmpty()) {
637  // Remove the last ,
638  dataSourceList = dataSourceList.substring(0, dataSourceList.length() - 1);
639  }
640 
641  return String.format(GEO_ARTIFACT_WITH_DATA_SOURCES_QUERY, GEO_ATTRIBUTE_TYPE_IDS,
642  dataSourceList);
643  }
644 
651  private interface ParserWithError<T> {
652 
653  T parse(BlackboardArtifact artifact) throws GeoLocationDataException;
654  }
655 
665  private static GeoLocationParseResult<Waypoint> parseWaypoint(ParserWithError<Waypoint> parser, BlackboardArtifact artifact) {
666  try {
667  return new GeoLocationParseResult<>(Arrays.asList(parser.parse(artifact)), true);
668  } catch (GeoLocationDataException ex) {
669  return new GeoLocationParseResult<>(null, false);
670  }
671  }
672 
682  private static GeoLocationParseResult<Waypoint> parseWaypoints(ParserWithError<List<Waypoint>> parser, BlackboardArtifact artifact) {
683  try {
684  return new GeoLocationParseResult<>(parser.parse(artifact), true);
685  } catch (GeoLocationDataException ignored) {
686  return new GeoLocationParseResult<>(null, false);
687  }
688  }
689 
698  private static GeoLocationParseResult<Waypoint> getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type) {
700  switch (type) {
701  case TSK_METADATA_EXIF:
702  waypoints.add(parseWaypoint(EXIFWaypoint::new, artifact));
703  break;
704  case TSK_GPS_BOOKMARK:
705  waypoints.add(parseWaypoint(BookmarkWaypoint::new, artifact));
706  break;
707  case TSK_GPS_TRACKPOINT:
708  waypoints.add(parseWaypoint(TrackpointWaypoint::new, artifact));
709  break;
710  case TSK_GPS_SEARCH:
711  waypoints.add(parseWaypoint(SearchWaypoint::new, artifact));
712  break;
713  case TSK_GPS_ROUTE:
714  waypoints.add(parseWaypoints((a) -> new Route(a).getRoute(), artifact));
715  break;
716  case TSK_GPS_LAST_KNOWN_LOCATION:
717  waypoints.add(parseWaypoint(LastKnownWaypoint::new, artifact));
718  break;
719  case TSK_GPS_TRACK:
720  waypoints.add(parseWaypoints((a) -> new Track(a).getPath(), artifact));
721  break;
722  default:
723  waypoints.add(parseWaypoint(CustomArtifactWaypoint::new, artifact));
724  }
725 
726  return waypoints;
727  }
728 }
static List< Waypoint > getLastKnownWaypoints(List< Waypoint > waypoints)
static String buildQuery(List< DataSource > dataSources, boolean showAll, int cntDaysFromRecent, boolean noTimeStamp)
static List< Waypoint > getBookmarkWaypoints(SleuthkitCase skCase)
static List< Waypoint > getBookmarkWaypoints(List< Waypoint > waypoints)
static void getAllWaypoints(SleuthkitCase skCase, List< DataSource > dataSources, List< ARTIFACT_TYPE > artifactTypes, boolean showAll, int cntDaysFromRecent, boolean noTimeStamp, WaypointFilterQueryCallBack queryCallBack)
static GeoLocationParseResult< Waypoint > parseWaypoints(ParserWithError< List< Waypoint >> parser, BlackboardArtifact artifact)
static GeoLocationParseResult< Waypoint > getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type)
static List< Waypoint > getSearchWaypoints(SleuthkitCase skCase)
static List< Waypoint > getSearchWaypoints(List< Waypoint > waypoints)
static List< Track > getTracks(List< Waypoint > waypoints)
static List< Waypoint > getTrackpointWaypoints(SleuthkitCase skCase)
static List< Route > getRoutes(List< Waypoint > waypoints)
static List< Waypoint > getAllWaypoints(SleuthkitCase skCase)
static String getWaypointListQuery(List< DataSource > dataSources)
static GeoLocationParseResult< Waypoint > parseWaypoint(ParserWithError< Waypoint > parser, BlackboardArtifact artifact)
static List< Waypoint > getEXIFWaypoints(List< Waypoint > waypoints)
static List< Waypoint > getTrackpointWaypoints(List< Waypoint > waypoints)
static String buildQueryForWaypointsWOTimeStamps(List< DataSource > dataSources)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static List< Waypoint > getLastKnownWaypoints(SleuthkitCase skCase)
static List< Waypoint > getEXIFWaypoints(SleuthkitCase skCase)
static List< Area > getAreas(List< Waypoint > waypoints)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.