Autopsy  4.17.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 
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  logger.log(Level.INFO, query);
494 
495  try {
496  // The CaseDBAccessManager.select function will add a SELECT
497  // to the beginning of the query
498  if (query.startsWith("SELECT")) { //NON-NLS
499  query = query.replaceFirst("SELECT", ""); //NON-NLS
500  }
501 
502  skCase.getCaseDbAccessManager().select(query, new CaseDbAccessManager.CaseDbAccessQueryCallback() {
503  @Override
504  public void process(ResultSet rs) {
506  try {
507  while (rs.next()) {
508  int artifact_type_id = rs.getInt("artifact_type_id"); //NON-NLS
509  long artifact_id = rs.getLong("artifact_id"); //NON-NLS
510 
511  ARTIFACT_TYPE type = ARTIFACT_TYPE.fromID(artifact_type_id);
512  if (artifactTypes.contains(type)) {
513  waypointResults.add(getWaypointForArtifact(skCase.getBlackboardArtifact(artifact_id), type));
514  }
515 
516  }
517 
518  queryCallBack.process(waypointResults);
519  } catch (SQLException | TskCoreException ex) {
520  logger.log(Level.WARNING, "Failed to filter waypoint.", ex); //NON-NLS
521  }
522 
523  }
524  });
525  } catch (TskCoreException ex) {
526  logger.log(Level.WARNING, "Failed to filter waypoint.", ex); //NON-NLS
527  }
528  }
529 
538  static private String buildQueryForWaypointsWOTimeStamps(List<DataSource> dataSources) {
539 
540 // SELECT_WO_TIMESTAMP
541 // SELECT DISTINCT artifact_id, artifact_type_id
542 // FROM blackboard_attributes
543 // WHERE artifact_id NOT IN (%s)
544 // AND artifact_id IN (%s)
545 // GEO_ARTIFACT_QUERY_ID_ONLY
546 // SELECT artifact_id
547 // FROM blackboard_attributes
548 // WHERE attribute_type_id IN (%d, %d)
549  return String.format(SELECT_WO_TIMESTAMP,
550  String.format(GEO_ARTIFACT_QUERY_ID_ONLY, TIME_TYPE_IDS),
551  getWaypointListQuery(dataSources));
552  }
553 
576  static private String buildQuery(List<DataSource> dataSources, boolean showAll, int cntDaysFromRecent, boolean noTimeStamp) {
577  String mostRecentQuery = "";
578 
579  if (!showAll && cntDaysFromRecent > 0) {
580 // MOST_RECENT_TIME
581 // SELECT MAX(value_int64) - (%d * 86400)
582 // FROM blackboard_attributes
583 // WHERE attribute_type_id IN(%s)
584 // AND artifact_id
585 // IN ( %s )
586 //
587  mostRecentQuery = String.format("AND value_int64 > (%s)", //NON-NLS
588  String.format(MOST_RECENT_TIME,
589  cntDaysFromRecent, TIME_TYPE_IDS,
590  getWaypointListQuery(dataSources)
591  ));
592  }
593 
594 // GEO_ARTIFACT_QUERY
595 // SELECT artifact_id, artifact_type_id
596 // FROM blackboard_attributes
597 // WHERE attribute_type_id IN (%s)
598  String query = String.format(GEO_ARTIFACT_QUERY, TIME_TYPE_IDS);
599 
600  // That are in the list of artifacts for the given data Sources
601  query += String.format("AND artifact_id IN(%s)", getWaypointListQuery(dataSources)); //NON-NLS
602  query += mostRecentQuery;
603 
604  if (showAll || noTimeStamp) {
605  query = String.format("%s UNION %s", buildQueryForWaypointsWOTimeStamps(dataSources), query); //NON-NLS
606  }
607 
608  return query;
609  }
610 
623  static private String getWaypointListQuery(List<DataSource> dataSources) {
624 
625  if (dataSources == null || dataSources.isEmpty()) {
626 // GEO_ARTIFACT_QUERY
627 // SELECT artifact_id, artifact_type_id
628 // FROM blackboard_attributes
629 // WHERE attribute_type_id IN (%s)
630  return String.format(GEO_ARTIFACT_QUERY, GEO_ATTRIBUTE_TYPE_IDS);
631  }
632 
633  String dataSourceList = "";
634  for (DataSource source : dataSources) {
635  dataSourceList += Long.toString(source.getId()) + ",";
636  }
637 
638  if (!dataSourceList.isEmpty()) {
639  // Remove the last ,
640  dataSourceList = dataSourceList.substring(0, dataSourceList.length() - 1);
641  }
642 
643  return String.format(GEO_ARTIFACT_WITH_DATA_SOURCES_QUERY, GEO_ATTRIBUTE_TYPE_IDS,
644  dataSourceList);
645  }
646 
653  private interface ParserWithError<T> {
654 
655  T parse(BlackboardArtifact artifact) throws GeoLocationDataException;
656  }
657 
667  private static GeoLocationParseResult<Waypoint> parseWaypoint(ParserWithError<Waypoint> parser, BlackboardArtifact artifact) {
668  try {
669  return new GeoLocationParseResult<>(Arrays.asList(parser.parse(artifact)), true);
670  } catch (GeoLocationDataException ex) {
671  return new GeoLocationParseResult<>(null, false);
672  }
673  }
674 
684  private static GeoLocationParseResult<Waypoint> parseWaypoints(ParserWithError<List<Waypoint>> parser, BlackboardArtifact artifact) {
685  try {
686  return new GeoLocationParseResult<>(parser.parse(artifact), true);
687  } catch (GeoLocationDataException ignored) {
688  return new GeoLocationParseResult<>(null, false);
689  }
690  }
691 
700  private static GeoLocationParseResult<Waypoint> getWaypointForArtifact(BlackboardArtifact artifact, ARTIFACT_TYPE type) {
702  switch (type) {
703  case TSK_METADATA_EXIF:
704  waypoints.add(parseWaypoint(EXIFWaypoint::new, artifact));
705  break;
706  case TSK_GPS_BOOKMARK:
707  waypoints.add(parseWaypoint(BookmarkWaypoint::new, artifact));
708  break;
709  case TSK_GPS_TRACKPOINT:
710  waypoints.add(parseWaypoint(TrackpointWaypoint::new, artifact));
711  break;
712  case TSK_GPS_SEARCH:
713  waypoints.add(parseWaypoint(SearchWaypoint::new, artifact));
714  break;
715  case TSK_GPS_ROUTE:
716  waypoints.add(parseWaypoints((a) -> new Route(a).getRoute(), artifact));
717  break;
718  case TSK_GPS_LAST_KNOWN_LOCATION:
719  waypoints.add(parseWaypoint(LastKnownWaypoint::new, artifact));
720  break;
721  case TSK_GPS_TRACK:
722  waypoints.add(parseWaypoints((a) -> new Track(a).getPath(), artifact));
723  break;
724  default:
725  waypoints.add(parseWaypoint(CustomArtifactWaypoint::new, artifact));
726  }
727 
728  return waypoints;
729  }
730 }
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-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.