diff --git a/bindings/java/src/org/sleuthkit/datamodel/TimelineEventTypes.java b/bindings/java/src/org/sleuthkit/datamodel/TimelineEventTypes.java index 0cade5baa5a5d2e6e1a7b70fa442b2cbee1c2fba..6444791cbf280a30ffa749c84a99f8b32148a0db 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/TimelineEventTypes.java +++ b/bindings/java/src/org/sleuthkit/datamodel/TimelineEventTypes.java @@ -142,7 +142,7 @@ public TimelineEventDescriptionWithTime makeEventDescription(BlackboardArtifact // Get the waypoint list "start time" GeoTrackPoints pointsList; try { - pointsList = BlackboardJsonAttrUtil.fromAttribute(attribute, GeoTrackPoints.class);; + pointsList = BlackboardJsonAttrUtil.fromAttribute(attribute, GeoTrackPoints.class); } catch (BlackboardJsonAttrUtil.InvalidJsonException ex) { throw new TskCoreException("Unable to parse track points in TSK_GEO_TRACKPOINTS attribute", ex); } diff --git a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/attributes/BlackboardJsonAttrUtil.java b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/attributes/BlackboardJsonAttrUtil.java new file mode 100755 index 0000000000000000000000000000000000000000..eea08024be1196c31c01fabde368514ccc4f09f4 --- /dev/null +++ b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/attributes/BlackboardJsonAttrUtil.java @@ -0,0 +1,118 @@ +/* + * Sleuth Kit Data Model + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier <at> sleuthkit <dot> 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.datamodel.blackboardutils.attributes; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import org.sleuthkit.datamodel.BlackboardAttribute; + +/** + * A utility for converting between JSON and artifact attributes of value type + * TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON. + */ +public final class BlackboardJsonAttrUtil { + + /** + * Creates an attribute of a given type with the string value set to an + * object of type T serialized to JSON. + * + * @param <T> The type of the attribute value object to be + * serailized. + * @param attrType The type of attribute to create. + * @param moduleName The name of the module creating the attribute. + * @param attrValue The attribute value object. + * + * @return The BlackboardAttribute object. + */ + public static <T> BlackboardAttribute toAttribute(BlackboardAttribute.Type attrType, String moduleName, T attrValue) { + if (attrType.getValueType() != BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON) { + throw new IllegalArgumentException(String.format("Attribute type %s does not have value type BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON", attrType.getTypeName())); + } + return new BlackboardAttribute(attrType, moduleName, (new Gson()).toJson(attrValue)); + } + + /** + * Creates an object of type T from the JSON in the string value of a + * BlackboardAttribute with a value type of + * TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON. + * + * @param <T> The type of the object to be created from the JSON. + * @param attr The attribute. + * @param clazz the class object for class T. + * + * @return The T object from the attribute. + * + * @throws InvalidJsonException Thrown the JSON in an artifact attribute + * cannot be deserialized to an object of the + * specified type. + */ + public static <T> T fromAttribute(BlackboardAttribute attr, Class<T> clazz) throws InvalidJsonException { + BlackboardAttribute.Type attrType = attr.getAttributeType(); + if (attrType.getValueType() != BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON) { + throw new IllegalArgumentException(String.format("Attribute type %s does not have value type BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON", attrType.getTypeName())); + } + String json = attr.getValueString(); + if (json == null || json.isEmpty()) { + throw new InvalidJsonException("The string value (JSON) of the attribute is null or empty"); + } + try { + T object = (new Gson()).fromJson(json, clazz); + return object; + } catch (JsonSyntaxException ex) { + throw new InvalidJsonException("The string value (JSON) of the attribute is of an unexpected type", ex); + } + } + + /** + * Constructs an exception to be thrown when the JSON in an artifact + * attribute cannot be deserialized to an object of the specified type. + */ + public static class InvalidJsonException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an exception thrown when JSON in an artifact attribute + * cannot be deserialized to an object of the specified type. + * + * @param message An error message. + */ + public InvalidJsonException(String message) { + super(message); + } + + /** + * Constructs an exception thrown when JSON in an artifact attribute + * cannot be deserialized to an object of the specified type. + * + * @param message An error message. + * @param cause An excception that caused this exception to be thrown. + */ + public InvalidJsonException(String message, Throwable cause) { + super(message, cause); + } + } + + /** + * Prevents instantiation of this utility class. + */ + private BlackboardJsonAttrUtil() { + } + +} diff --git a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/attributes/GeoTrackPoints.java b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/attributes/GeoTrackPoints.java new file mode 100755 index 0000000000000000000000000000000000000000..fb61d5a53bd4234cf2d023a3e1a51fd0d20b807c --- /dev/null +++ b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/attributes/GeoTrackPoints.java @@ -0,0 +1,232 @@ +/* + * Sleuth Kit Data Model + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier <at> sleuthkit <dot> 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.datamodel.blackboardutils.attributes; + +import com.google.gson.annotations.SerializedName; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * A GeoTrackPoints object is a collection of TrackPoint objects. A TrackPoint + * represents a track point, which is a location in a geographic coordinate + * system with latitude, longitude and altitude (elevation) axes. + * + * GeoTrackPoints objects are designed to be used as the string value of the + * TSK_GEO_TRACKPOINTS attribute of a TSK_GPS_TRACK artifact. TSK_GPS_TRACK + * artifacts are used to record a track, or path, of a GPS-enabled device as a + * connected series of track points. + * + */ +public class GeoTrackPoints implements Iterable<GeoTrackPoints.TrackPoint> { + + private final List<TrackPoint> pointList; + + /** + * Constructs an empty GeoTrackPoints object. + */ + public GeoTrackPoints() { + pointList = new ArrayList<>(); + } + + /** + * Adds a track point to this list of track points. + * + * @param trackPoint A track point. + */ + public void addPoint(TrackPoint trackPoint) { + if (trackPoint == null) { + throw new IllegalArgumentException("addPoint was passed a null track point"); + } + + pointList.add(trackPoint); + } + + @Override + public Iterator<TrackPoint> iterator() { + return pointList.iterator(); + } + + /** + * Returns whether or not this list of track points is empty. + * + * @return True or false. + */ + public boolean isEmpty() { + return pointList.isEmpty(); + } + + /** + * Gets the earliest track point timestamp in this list of track points, if + * timestamps are present. + * + * @return The timestamp in milliseconds from the Java epoch of + * 1970-01-01T00:00:00Z, may be null or zero. + */ + public Long getStartTime() { + List<TrackPoint> orderedPoints = getTimeOrderedPoints(); + if (orderedPoints != null) { + for (TrackPoint point : orderedPoints) { + if (point.getTimeStamp() != null) { + return point.getTimeStamp(); + } + } + } + return null; + } + + /** + * Gets the latest track point timestamp in this list of track points, if + * timestamps are present. + * + * @return The timestamp in milliseconds from the Java epoch of + * 1970-01-01T00:00:00Z, may be null or zero. + */ + public Long getEndTime() { + List<TrackPoint> orderedPoints = getTimeOrderedPoints(); + if (orderedPoints != null) { + for (int index = orderedPoints.size() - 1; index >= 0; index--) { + TrackPoint point = orderedPoints.get(index); + if (point.getTimeStamp() != null) { + return point.getTimeStamp(); + } + } + } + return null; + } + + /** + * Gets this list of track points as a list ordered by track point + * timestamp. + * + * @return The ordered list of track points. + */ + private List<TrackPoint> getTimeOrderedPoints() { + return pointList.stream().sorted().collect(Collectors.toCollection(ArrayList::new)); + } + + /** + * A representation of a track point, which is a location in a geographic + * coordinate system with latitude, longitude and altitude (elevation) axes. + */ + public final static class TrackPoint extends GeoWaypoints.Waypoint implements Comparable<TrackPoint> { + + @SerializedName("TSK_GEO_VELOCITY") + private final Double velocity; + @SerializedName("TSK_DISTANCE_FROM_HOMEPOINT") + private final Double distanceFromHomePoint; + @SerializedName("TSK_DISTANCE_TRAVELED") + private final Double distanceTraveled; + @SerializedName("TSK_DATETIME") + private final Long timestamp; + + /** + * Constructs a representation of a track point, which is a location in + * a geographic coordinate system with latitude, longitude and altitude + * (elevation) axes. + * + * @param latitude The latitude of the track point. + * @param longitude The longitude of the track point. + * @param altitude The altitude of the track point, may be + * null. + * @param name The name of the track point, may be + * null. + * @param velocity The velocity of the device at the track + * point in meters per second, may be null. + * @param distanceFromHomePoint The distance of the track point in + * meters from an established home point, + * may be null. + * @param distanceTraveled The distance the device has traveled in + * meters at the time this track point was + * created, may be null. + * @param timestamp The timestamp of the track point as + * milliseconds from the Java epoch of + * 1970-01-01T00:00:00Z, may be null. + */ + public TrackPoint(Double latitude, + Double longitude, + Double altitude, + String name, + Double velocity, + Double distanceFromHomePoint, + Double distanceTraveled, + Long timestamp) { + super(latitude, longitude, altitude, name); + this.velocity = velocity; + this.distanceFromHomePoint = distanceFromHomePoint; + this.distanceTraveled = distanceTraveled; + this.timestamp = timestamp; + } + + /** + * Gets the velocity of the device at this track point in meters per + * second, if known. + * + * @return The velocity in meters/sec, may be null or zero. + */ + public Double getVelocity() { + return velocity; + } + + /** + * Gets the distance of this track point from an established home point, + * if known. + * + * @return The distance in meters, may be null or zero. + */ + public Double getDistanceFromHomePoint() { + return distanceFromHomePoint; + } + + /** + * Gets the distance the device has traveled in meters at the time this + * track point was created, if known. + * + * @return The distance traveled in meters, may be null or zero. + */ + public Double getDistanceTraveled() { + return distanceTraveled; + } + + /** + * Gets the timestamp of this track point as milliseconds from the Java + * epoch of 1970-01-01T00:00:00Z, if known. + * + * @return The timestamp, may be null or zero. + */ + public Long getTimeStamp() { + return timestamp; + } + + @Override + public int compareTo(TrackPoint otherTP) { + Long otherTimeStamp = otherTP.getTimeStamp(); + + if (timestamp == null && otherTimeStamp != null) { + return -1; + } else if (timestamp != null && otherTimeStamp == null) { + return 1; + } else { + return timestamp.compareTo(otherTP.getTimeStamp()); + } + } + } + +} diff --git a/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/attributes/GeoWaypoints.java b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/attributes/GeoWaypoints.java new file mode 100755 index 0000000000000000000000000000000000000000..4e5f3ca192dd5816e26927e8b9b30951f5b1f412 --- /dev/null +++ b/bindings/java/src/org/sleuthkit/datamodel/blackboardutils/attributes/GeoWaypoints.java @@ -0,0 +1,153 @@ +/* + * Sleuth Kit Data Model + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier <at> sleuthkit <dot> 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.datamodel.blackboardutils.attributes; + +import com.google.gson.annotations.SerializedName; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * A GeoWaypoints object is a collection of Waypoint objects. A Waypoint object + * represents a waypoint for a GPS-enabled device with a navigation capability. + * Every waypoint is a location, possibly named, in a geographic coordinate + * system with latitude, longitude and altitude (elevation) axes. + * + * GeoWaypoints objects are designed to be used as the string value of the + * TSK_GEO_WAYPOINTS attribute of a TSK_GPS_ROUTE artifact. TSK_GPS_ROUTE + * artifacts are used to record one or more waypoints linked together as a route + * to be navigated from waypoint to waypoint. + */ +public class GeoWaypoints implements Iterable<GeoWaypoints.Waypoint> { + + private final List<Waypoint> points; + + /** + * Constructs an empty GeoWaypoints object. + */ + public GeoWaypoints() { + points = new ArrayList<>(); + } + + /** + * Adds a waypoint to this list of waypoints. + * + * @param wayPoint A waypoint. + */ + public void addPoint(Waypoint wayPoint) { + if (wayPoint == null) { + throw new IllegalArgumentException("addPoint was passed a null waypoint"); + } + + points.add(wayPoint); + } + + /** + * Returns whether or not this list of waypoints is empty. + * + * @return True or false. + */ + public boolean isEmpty() { + return points.isEmpty(); + } + + @Override + public Iterator<Waypoint> iterator() { + return points.iterator(); + } + + /** + * A representation of a waypoint, which is a a location, possibly named, in + * a geographic coordinate system with latitude, longitude and altitude + * (elevation) axes. + */ + public static class Waypoint { + + @SerializedName("TSK_GEO_LATITUDE") + private final Double latitude; + @SerializedName("TSK_GEO_LONGITUDE") + private final Double longitude; + @SerializedName("TSK_GEO_ALTITUDE") + private final Double altitude; + @SerializedName("TSK_NAME") + private final String name; + + /** + * Constructs a representation of a waypoint, which is a a location, + * possibly named, in a geographic coordinate system with latitude, + * longitude and altitude (elevation) axes. + * + * @param latitude The latitude of the waypoint. + * @param longitude The longitude of the waypoint. + * @param altitude The altitude of the waypoint, may be null. + * @param name The name of the waypoint, may be null. + */ + public Waypoint(Double latitude, Double longitude, Double altitude, String name) { + if (latitude == null) { + throw new IllegalArgumentException("Constructor was passed null latitude"); + } + + if (longitude == null) { + throw new IllegalArgumentException("Constructor was passed null longitude"); + } + + this.latitude = latitude; + this.longitude = longitude; + this.altitude = altitude; + this.name = name; + } + + /** + * Gets the latitude of this waypoint. + * + * @return The latitude. + */ + public Double getLatitude() { + return latitude; + } + + /** + * Gets the longitude of this waypoint. + * + * @return The longitude. + */ + public Double getLongitude() { + return longitude; + } + + /** + * Gets the altitude of this waypoint, if available. + * + * @return The altitude, may be null or zero. + */ + public Double getAltitude() { + return altitude; + } + + /** + * Gets the name of this waypoint, if available. + * + * @return The name, may be null or empty. + */ + public String getName() { + return name; + } + } + +}