Autopsy  4.15.0
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 
191  @SuppressWarnings("deprecation")
192  public static List<Waypoint> getTrackpointWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
193  List<BlackboardArtifact> artifacts = null;
194  try {
195  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_GPS_TRACKPOINT);
196  } catch (TskCoreException ex) {
197  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_TRACKPOINT", ex);//NON-NLS
198  }
199 
200  List<Waypoint> points = new ArrayList<>();
201  for (BlackboardArtifact artifact : artifacts) {
202  try {
203  Waypoint point = new TrackpointWaypoint(artifact);
204  points.add(point);
205  } catch (GeoLocationDataException ex) {
206  logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_TRACKPOINT artifactID: %d", artifact.getArtifactID()));//NON-NLS
207  }
208  }
209  return points;
210  }
211 
219  public static List<Waypoint> getTrackpointWaypoints(List<Waypoint> waypoints) {
220  List<Waypoint> specificPoints = new ArrayList<>();
221 
222  for (Waypoint point : waypoints) {
223  if (point instanceof TrackpointWaypoint) {
224  specificPoints.add(point);
225  }
226  }
227 
228  return specificPoints;
229  }
230 
240  static public List<Waypoint> getEXIFWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
241  List<BlackboardArtifact> artifacts = null;
242  try {
243  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_METADATA_EXIF);
244  } catch (TskCoreException ex) {
245  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_LAST_KNOWN_LOCATION", ex);//NON-NLS
246  }
247 
248  List<Waypoint> points = new ArrayList<>();
249  if (artifacts != null) {
250  for (BlackboardArtifact artifact : artifacts) {
251  try {
252  Waypoint point = new EXIFWaypoint(artifact);
253  points.add(point);
254  } catch (GeoLocationDataException ex) {
255  // I am a little relucant to log this error because I suspect
256  // this will happen more often than not. It is valid for
257  // METADAT_EXIF to not have longitude and latitude
258  }
259  }
260  }
261  return points;
262  }
263 
271  public static List<Waypoint> getEXIFWaypoints(List<Waypoint> waypoints) {
272  List<Waypoint> specificPoints = new ArrayList<>();
273 
274  for (Waypoint point : waypoints) {
275  if (point instanceof EXIFWaypoint) {
276  specificPoints.add(point);
277  }
278  }
279 
280  return specificPoints;
281  }
282 
292  public static List<Waypoint> getSearchWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
293  List<BlackboardArtifact> artifacts = null;
294  try {
295  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_GPS_SEARCH);
296  } catch (TskCoreException ex) {
297  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_SEARCH", ex);//NON-NLS
298  }
299 
300  List<Waypoint> points = new ArrayList<>();
301  if (artifacts != null) {
302  for (BlackboardArtifact artifact : artifacts) {
303  try {
304  Waypoint point = new SearchWaypoint(artifact);
305  points.add(point);
306  } catch (GeoLocationDataException ex) {
307  logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_SEARCH artifactID: %d", artifact.getArtifactID()));//NON-NLS
308  }
309  }
310  }
311  return points;
312  }
313 
321  public static List<Waypoint> getSearchWaypoints(List<Waypoint> waypoints) {
322  List<Waypoint> specificPoints = new ArrayList<>();
323 
324  for (Waypoint point : waypoints) {
325  if (point instanceof SearchWaypoint) {
326  specificPoints.add(point);
327  }
328  }
329 
330  return specificPoints;
331  }
332 
342  public static List<Waypoint> getLastKnownWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
343  List<BlackboardArtifact> artifacts = null;
344  try {
345  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION);
346  } catch (TskCoreException ex) {
347  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_LAST_KNOWN_LOCATION", ex);//NON-NLS
348  }
349 
350  List<Waypoint> points = new ArrayList<>();
351  if (artifacts != null) {
352  for (BlackboardArtifact artifact : artifacts) {
353  try {
354  Waypoint point = new LastKnownWaypoint(artifact);
355  points.add(point);
356  } catch (GeoLocationDataException ex) {
357  logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_LAST_KNOWN_LOCATION artifactID: %d", artifact.getArtifactID()));//NON-NLS
358  }
359  }
360  }
361  return points;
362  }
363 
372  public static List<Waypoint> getLastKnownWaypoints(List<Waypoint> waypoints) {
373  List<Waypoint> specificPoints = new ArrayList<>();
374 
375  for (Waypoint point : waypoints) {
376  if (point instanceof LastKnownWaypoint) {
377  specificPoints.add(point);
378  }
379  }
380 
381  return specificPoints;
382  }
383 
393  public static List<Waypoint> getBookmarkWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
394  List<BlackboardArtifact> artifacts = null;
395  try {
396  artifacts = skCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_GPS_BOOKMARK);
397  } catch (TskCoreException ex) {
398  throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_BOOKMARK", ex);//NON-NLS
399  }
400 
401  List<Waypoint> points = new ArrayList<>();
402  if (artifacts != null) {
403  for (BlackboardArtifact artifact : artifacts) {
404  try {
405  Waypoint point = new BookmarkWaypoint(artifact);
406  points.add(point);
407  } catch (GeoLocationDataException ex) {
408  logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_BOOKMARK artifactID: %d", artifact.getArtifactID()), ex);//NON-NLS
409  }
410  }
411  }
412  return points;
413  }
414 
423  public static List<Waypoint> getBookmarkWaypoints(List<Waypoint> waypoints) {
424  List<Waypoint> specificPoints = new ArrayList<>();
425 
426  for (Waypoint point : waypoints) {
427  if (point instanceof BookmarkWaypoint) {
428  specificPoints.add(point);
429  }
430  }
431 
432  return specificPoints;
433  }
434 
468  static public void getAllWaypoints(SleuthkitCase skCase, List<DataSource> dataSources, List<ARTIFACT_TYPE> artifactTypes, boolean showAll, int cntDaysFromRecent, boolean noTimeStamp, WaypointFilterQueryCallBack queryCallBack) throws GeoLocationDataException {
469  String query = buildQuery(dataSources, showAll, cntDaysFromRecent, noTimeStamp);
470 
471  logger.log(Level.INFO, query);
472 
473  try {
474  // The CaseDBAccessManager.select function will add a SELECT
475  // to the beginning of the query
476  if (query.startsWith("SELECT")) { //NON-NLS
477  query = query.replaceFirst("SELECT", ""); //NON-NLS
478  }
479 
480  skCase.getCaseDbAccessManager().select(query, new CaseDbAccessManager.CaseDbAccessQueryCallback() {
481  @Override
482  public void process(ResultSet rs) {
484  try {
485  while (rs.next()) {
486  int artifact_type_id = rs.getInt("artifact_type_id"); //NON-NLS
487  long artifact_id = rs.getLong("artifact_id"); //NON-NLS
488 
489  ARTIFACT_TYPE type = ARTIFACT_TYPE.fromID(artifact_type_id);
490  if (artifactTypes.contains(type)) {
491  waypointResults.add(getWaypointForArtifact(skCase.getBlackboardArtifact(artifact_id), type));
492  }
493 
494  }
495 
496  queryCallBack.process(waypointResults);
497  } catch (SQLException | TskCoreException ex) {
498  logger.log(Level.WARNING, "Failed to filter waypoint.", ex); //NON-NLS
499  }
500 
501  }
502  });
503  } catch (TskCoreException ex) {
504  logger.log(Level.WARNING, "Failed to filter waypoint.", ex); //NON-NLS
505  }
506  }
507 
516  static private String buildQueryForWaypointsWOTimeStamps(List<DataSource> dataSources) {
517 
518 // SELECT_WO_TIMESTAMP
519 // SELECT DISTINCT artifact_id, artifact_type_id
520 // FROM blackboard_attributes
521 // WHERE artifact_id NOT IN (%s)
522 // AND artifact_id IN (%s)
523 // GEO_ARTIFACT_QUERY_ID_ONLY
524 // SELECT artifact_id
525 // FROM blackboard_attributes
526 // WHERE attribute_type_id IN (%d, %d)
527  return String.format(SELECT_WO_TIMESTAMP,
528  String.format(GEO_ARTIFACT_QUERY_ID_ONLY, TIME_TYPE_IDS),
529  getWaypointListQuery(dataSources));
530  }
531 
554  static private String buildQuery(List<DataSource> dataSources, boolean showAll, int cntDaysFromRecent, boolean noTimeStamp) {
555  String mostRecentQuery = "";
556 
557  if (!showAll && cntDaysFromRecent > 0) {
558 // MOST_RECENT_TIME
559 // SELECT MAX(value_int64) - (%d * 86400)
560 // FROM blackboard_attributes
561 // WHERE attribute_type_id IN(%s)
562 // AND artifact_id
563 // IN ( %s )
564 //
565  mostRecentQuery = String.format("AND value_int64 > (%s)", //NON-NLS
566  String.format(MOST_RECENT_TIME,
567  cntDaysFromRecent, TIME_TYPE_IDS,
568  getWaypointListQuery(dataSources)
569  ));
570  }
571 
572 // GEO_ARTIFACT_QUERY
573 // SELECT artifact_id, artifact_type_id
574 // FROM blackboard_attributes
575 // WHERE attribute_type_id IN (%s)
576  String query = String.format(GEO_ARTIFACT_QUERY, TIME_TYPE_IDS);
577 
578  // That are in the list of artifacts for the given data Sources
579  query += String.format("AND artifact_id IN(%s)", getWaypointListQuery(dataSources)); //NON-NLS
580  query += mostRecentQuery;
581 
582  if (showAll || noTimeStamp) {
583  query = String.format("%s UNION %s", buildQueryForWaypointsWOTimeStamps(dataSources), query); //NON-NLS
584  }
585 
586  return query;
587  }
588 
601  static private String getWaypointListQuery(List<DataSource> dataSources) {
602 
603  if (dataSources == null || dataSources.isEmpty()) {
604 // GEO_ARTIFACT_QUERY
605 // SELECT artifact_id, artifact_type_id
606 // FROM blackboard_attributes
607 // WHERE attribute_type_id IN (%s)
608  return String.format(GEO_ARTIFACT_QUERY, GEO_ATTRIBUTE_TYPE_IDS);
609  }
610 
611  String dataSourceList = "";
612  for (DataSource source : dataSources) {
613  dataSourceList += Long.toString(source.getId()) + ",";
614  }
615 
616  if (!dataSourceList.isEmpty()) {
617  // Remove the last ,
618  dataSourceList = dataSourceList.substring(0, dataSourceList.length() - 1);
619  }
620 
621  return String.format(GEO_ARTIFACT_WITH_DATA_SOURCES_QUERY, GEO_ATTRIBUTE_TYPE_IDS,
622  dataSourceList);
623  }
624 
631  private interface ParserWithError<T> {
632 
633  T parse(BlackboardArtifact artifact) throws GeoLocationDataException;
634  }
635 
645  private static GeoLocationParseResult<Waypoint> parseWaypoint(ParserWithError<Waypoint> parser, BlackboardArtifact artifact) {
646  try {
647  return new GeoLocationParseResult<>(Arrays.asList(parser.parse(artifact)), true);
648  } catch (GeoLocationDataException ex) {
649  return new GeoLocationParseResult<>(null, false);
650  }
651  }
652 
662  private static GeoLocationParseResult<Waypoint> parseWaypoints(ParserWithError<List<Waypoint>> parser, BlackboardArtifact artifact) {
663  try {
664  return new GeoLocationParseResult<>(parser.parse(artifact), true);
665  } catch (GeoLocationDataException ignored) {
666  return new GeoLocationParseResult<>(null, false);
667  }
668  }
669 
678  private static GeoLocationParseResult<Waypoint> getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type) {
680  switch (type) {
681  case TSK_METADATA_EXIF:
682  waypoints.add(parseWaypoint(EXIFWaypoint::new, artifact));
683  break;
684  case TSK_GPS_BOOKMARK:
685  waypoints.add(parseWaypoint(BookmarkWaypoint::new, artifact));
686  break;
687  case TSK_GPS_TRACKPOINT:
688  waypoints.add(parseWaypoint(TrackpointWaypoint::new, artifact));
689  break;
690  case TSK_GPS_SEARCH:
691  waypoints.add(parseWaypoint(SearchWaypoint::new, artifact));
692  break;
693  case TSK_GPS_ROUTE:
694  waypoints.add(parseWaypoints((a) -> new Route(a).getRoute(), artifact));
695  break;
696  case TSK_GPS_LAST_KNOWN_LOCATION:
697  waypoints.add(parseWaypoint(LastKnownWaypoint::new, artifact));
698  break;
699  case TSK_GPS_TRACK:
700  waypoints.add(parseWaypoints((a) -> new Track(a).getPath(), artifact));
701  break;
702  default:
703  waypoints.add(parseWaypoint(CustomArtifactWaypoint::new, artifact));
704  }
705 
706  return waypoints;
707  }
708 }
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)

Copyright © 2012-2020 Basis Technology. Generated on: Mon Jul 6 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.