mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 10:17:41 +00:00
merged in geolocation-refactor-branch
This commit is contained in:
commit
3f16ff384e
36
.travis.yml
36
.travis.yml
@ -1,8 +1,11 @@
|
||||
language: java
|
||||
sudo: required
|
||||
dist: bionic
|
||||
os:
|
||||
- linux
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- os: linux
|
||||
dist: bionic
|
||||
- os: osx
|
||||
|
||||
env:
|
||||
global:
|
||||
@ -12,6 +15,7 @@ addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- testdisk
|
||||
- libafflib-dev
|
||||
- libewf-dev
|
||||
- libpq-dev
|
||||
@ -29,11 +33,13 @@ addons:
|
||||
update: true
|
||||
packages:
|
||||
- ant
|
||||
- ant-optional
|
||||
- wget
|
||||
- libpq
|
||||
- libewf
|
||||
- gettext
|
||||
- cppunit
|
||||
- afflib
|
||||
- testdisk
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
@ -43,9 +49,7 @@ before_install:
|
||||
- python setupSleuthkitBranch.py
|
||||
|
||||
install:
|
||||
- sudo apt-get install testdisk
|
||||
- cd sleuthkit/sleuthkit
|
||||
- ./travis_install_libs.sh
|
||||
- pushd sleuthkit/sleuthkit && ./travis_install_libs.sh && popd
|
||||
|
||||
before_script:
|
||||
- if [ $TRAVIS_OS_NAME = linux ]; then
|
||||
@ -54,13 +58,13 @@ before_script:
|
||||
export PATH=/usr/bin:$PATH;
|
||||
unset JAVA_HOME;
|
||||
fi
|
||||
- if [ $TRAVIS_OS_NAME = osx ]; then
|
||||
brew uninstall java --force;
|
||||
brew cask uninstall java --force;
|
||||
brew tap homebrew/cask-versions;
|
||||
brew cask install corretto8;
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home;
|
||||
fi
|
||||
- java -version
|
||||
|
||||
script:
|
||||
- set -e
|
||||
- echo "Building TSK..."
|
||||
- ./bootstrap && ./configure --prefix=/usr && make
|
||||
- pushd bindings/java/ && ant -q dist-PostgreSQL && popd
|
||||
- echo "Building Autopsy..." && echo -en 'travis_fold:start:script.build\\r'
|
||||
- cd $TRAVIS_BUILD_DIR/
|
||||
- ant build
|
||||
- echo -en 'travis_fold:end:script.build\\r'
|
||||
script: ./travis_build.sh
|
||||
|
@ -56,6 +56,10 @@ import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
import org.netbeans.swing.etable.ETable;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
* Instances of this class display the BlackboardArtifacts associated with the
|
||||
@ -552,6 +556,16 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
value = dateFormatter.format(new java.util.Date(epoch * 1000));
|
||||
}
|
||||
break;
|
||||
case JSON:
|
||||
// @TODO: 5726 - return a multilevel bulleted list instead of prettyprint JSON
|
||||
String jsonVal = attr.getValueString();
|
||||
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject json = parser.parse(jsonVal).getAsJsonObject();
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
value = gson.toJson(json);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Attribute sources column.
|
||||
|
@ -122,6 +122,7 @@ public class ArtifactStringContent implements StringContent {
|
||||
case LONG:
|
||||
case DOUBLE:
|
||||
case BYTE:
|
||||
case JSON:
|
||||
default:
|
||||
value = attr.getDisplayString();
|
||||
break;
|
||||
|
@ -38,12 +38,10 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.Route;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.ArtifactWaypoint;
|
||||
import org.sleuthkit.autopsy.geolocation.datamodel.Waypoint;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@ -56,7 +54,7 @@ final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewer.viewe
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MapWaypoint.class.getName());
|
||||
|
||||
private final ArtifactWaypoint dataModelWaypoint;
|
||||
private final Waypoint dataModelWaypoint;
|
||||
private final GeoPosition position;
|
||||
|
||||
/**
|
||||
@ -64,7 +62,7 @@ final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewer.viewe
|
||||
*
|
||||
* @param dataModelWaypoint The datamodel waypoint to wrap
|
||||
*/
|
||||
private MapWaypoint(ArtifactWaypoint dataModelWaypoint) {
|
||||
private MapWaypoint(Waypoint dataModelWaypoint) {
|
||||
super(dataModelWaypoint.getLatitude(), dataModelWaypoint.getLongitude());
|
||||
this.dataModelWaypoint = dataModelWaypoint;
|
||||
position = new GeoPosition(dataModelWaypoint.getLatitude(), dataModelWaypoint.getLongitude());
|
||||
@ -86,7 +84,7 @@ final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewer.viewe
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
static List<MapWaypoint> getWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
List<ArtifactWaypoint> points = ArtifactWaypoint.getAllWaypoints(skCase);
|
||||
List<Waypoint> points = Waypoint.getAllWaypoints(skCase);
|
||||
|
||||
List<Route> routes = Route.getRoutes(skCase);
|
||||
for (Route route : routes) {
|
||||
@ -95,7 +93,7 @@ final class MapWaypoint extends KdTree.XYZPoint implements org.jxmapviewer.viewe
|
||||
|
||||
List<MapWaypoint> mapPoints = new ArrayList<>();
|
||||
|
||||
for (ArtifactWaypoint point : points) {
|
||||
for (Waypoint point : points) {
|
||||
mapPoints.add(new MapWaypoint(point));
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
/**
|
||||
* Waypoint wrapper class for TSK_METADATA_EXIF artifacts.
|
||||
*/
|
||||
final class EXIFWaypoint extends ArtifactWaypoint {
|
||||
final class EXIFWaypoint extends Waypoint {
|
||||
|
||||
/**
|
||||
* Construct a way point with the given artifact.
|
||||
|
@ -26,7 +26,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
/**
|
||||
* A Last Known Location Waypoint object.
|
||||
*/
|
||||
final class LastKnownWaypoint extends ArtifactWaypoint {
|
||||
final class LastKnownWaypoint extends Waypoint {
|
||||
|
||||
/**
|
||||
* Constructs a new waypoint.
|
||||
|
@ -36,12 +36,12 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
*
|
||||
*/
|
||||
public final class Route {
|
||||
private final List<ArtifactWaypoint> points;
|
||||
private final List<Waypoint> points;
|
||||
private final Long timestamp;
|
||||
|
||||
// This list is not expected to change after construction so the
|
||||
// constructor will take care of creating an unmodifiable List
|
||||
private final List<ArtifactWaypoint.Property> immutablePropertiesList;
|
||||
private final List<Waypoint.Property> immutablePropertiesList;
|
||||
|
||||
/**
|
||||
* Gets the list of Routes from the TSK_GPS_ROUTE artifacts.
|
||||
@ -77,14 +77,14 @@ public final class Route {
|
||||
Route(BlackboardArtifact artifact) throws GeoLocationDataException {
|
||||
points = new ArrayList<>();
|
||||
|
||||
Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap = ArtifactWaypoint.getAttributesFromArtifactAsMap(artifact);
|
||||
Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap = Waypoint.getAttributesFromArtifactAsMap(artifact);
|
||||
points.add(getRouteStartPoint(artifact, attributeMap));
|
||||
points.add(getRouteEndPoint(artifact, attributeMap));
|
||||
|
||||
BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
|
||||
timestamp = attribute != null ? attribute.getValueLong() : null;
|
||||
|
||||
immutablePropertiesList = Collections.unmodifiableList(ArtifactWaypoint.createGeolocationProperties(attributeMap));
|
||||
immutablePropertiesList = Collections.unmodifiableList(Waypoint.createGeolocationProperties(attributeMap));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,7 +92,7 @@ public final class Route {
|
||||
*
|
||||
* @return List an unmodifiableList of ArtifactWaypoints for this route
|
||||
*/
|
||||
public List<ArtifactWaypoint> getRoute() {
|
||||
public List<Waypoint> getRoute() {
|
||||
return Collections.unmodifiableList(points);
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ public final class Route {
|
||||
*
|
||||
* @return Map of key, value pairs.
|
||||
*/
|
||||
public List<ArtifactWaypoint.Property> getOtherProperties() {
|
||||
public List<Waypoint.Property> getOtherProperties() {
|
||||
return immutablePropertiesList;
|
||||
}
|
||||
|
||||
@ -136,14 +136,15 @@ public final class Route {
|
||||
@Messages({
|
||||
"Route_Start_Label=Start"
|
||||
})
|
||||
private ArtifactWaypoint getRouteStartPoint(BlackboardArtifact artifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
|
||||
|
||||
private Waypoint getRouteStartPoint(BlackboardArtifact artifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
|
||||
BlackboardAttribute latitude = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
|
||||
BlackboardAttribute longitude = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
|
||||
BlackboardAttribute altitude = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
|
||||
BlackboardAttribute pointTimestamp = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
|
||||
|
||||
if (latitude != null && longitude != null) {
|
||||
return new ArtifactWaypoint(artifact,
|
||||
return new Waypoint(artifact,
|
||||
Bundle.Route_Start_Label(),
|
||||
pointTimestamp != null ? pointTimestamp.getValueLong() : null,
|
||||
latitude.getValueDouble(),
|
||||
@ -169,14 +170,15 @@ public final class Route {
|
||||
@Messages({
|
||||
"Route_End_Label=End"
|
||||
})
|
||||
private ArtifactWaypoint getRouteEndPoint(BlackboardArtifact artifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
|
||||
Waypoint getRouteEndPoint(BlackboardArtifact artifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
|
||||
BlackboardAttribute latitude = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
|
||||
BlackboardAttribute longitude = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END);
|
||||
BlackboardAttribute altitude = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
|
||||
BlackboardAttribute pointTimestamp = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
|
||||
|
||||
if (latitude != null && longitude != null) {
|
||||
return new ArtifactWaypoint(artifact,
|
||||
|
||||
return new Waypoint(artifact,
|
||||
Bundle.Route_End_Label(),
|
||||
pointTimestamp != null ? pointTimestamp.getValueLong() : null,
|
||||
latitude.getValueDouble(),
|
||||
|
@ -24,9 +24,9 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
|
||||
/**
|
||||
* A SearchWaypoint is a subclass of ArtifactWaypoint.
|
||||
* A SearchWaypoint is a subclass of Waypoint.
|
||||
*/
|
||||
final class SearchWaypoint extends ArtifactWaypoint {
|
||||
final class SearchWaypoint extends Waypoint {
|
||||
|
||||
/**
|
||||
* Construct a waypoint for TSK_GPS_SEARCH artifact.
|
||||
|
@ -26,7 +26,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
/**
|
||||
* A wrapper class for TSK_GPS_TRACKPOINT artifacts.
|
||||
*/
|
||||
final class TrackpointWaypoint extends ArtifactWaypoint {
|
||||
final class TrackpointWaypoint extends Waypoint {
|
||||
/**
|
||||
* Construct a waypoint for trackpoints.
|
||||
*
|
||||
|
@ -37,7 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* Representation of a Waypoint created from a BlackboardArtifact.
|
||||
*
|
||||
*/
|
||||
public class ArtifactWaypoint {
|
||||
public class Waypoint {
|
||||
|
||||
final private Long timestamp;
|
||||
final private Double longitude;
|
||||
@ -50,13 +50,13 @@ public class ArtifactWaypoint {
|
||||
|
||||
// This list is not expected to change after construction. The
|
||||
// constructor will take care of making an unmodifiable List
|
||||
final private List<ArtifactWaypoint.Property> immutablePropertiesList;
|
||||
final private List<Waypoint.Property> immutablePropertiesList;
|
||||
|
||||
/**
|
||||
* This is a list of attributes that are already being handled by the
|
||||
* by getter functions.
|
||||
*/
|
||||
static BlackboardAttribute.ATTRIBUTE_TYPE[] ALREADY_HANDLED_ATTRIBUTES = {
|
||||
static private BlackboardAttribute.ATTRIBUTE_TYPE[] ALREADY_HANDLED_ATTRIBUTES = {
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE,
|
||||
@ -68,7 +68,7 @@ public class ArtifactWaypoint {
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END,};
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ArtifactWaypoint.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(Waypoint.class.getName());
|
||||
|
||||
/**
|
||||
* Construct a waypoint with the given artifact.
|
||||
@ -78,7 +78,7 @@ public class ArtifactWaypoint {
|
||||
* @throws GeoLocationDataException Exception will be thrown if artifact did
|
||||
* not have a valid longitude and latitude.
|
||||
*/
|
||||
ArtifactWaypoint(BlackboardArtifact artifact) throws GeoLocationDataException {
|
||||
Waypoint(BlackboardArtifact artifact) throws GeoLocationDataException {
|
||||
this(artifact,
|
||||
getAttributesFromArtifactAsMap(artifact));
|
||||
}
|
||||
@ -98,7 +98,7 @@ public class ArtifactWaypoint {
|
||||
* @throws GeoLocationDataException Exception will be thrown if artifact did
|
||||
* not have a valid longitude and latitude.
|
||||
*/
|
||||
ArtifactWaypoint(BlackboardArtifact artifact, String label, Long timestamp, Double latitude, Double longitude, Double altitude, AbstractFile image, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap, Route route) throws GeoLocationDataException {
|
||||
Waypoint(BlackboardArtifact artifact, String label, Long timestamp, Double latitude, Double longitude, Double altitude, AbstractFile image, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap, Route route) throws GeoLocationDataException {
|
||||
if (longitude == null || latitude == null) {
|
||||
throw new GeoLocationDataException("Invalid waypoint, null value passed for longitude or latitude");
|
||||
}
|
||||
@ -124,7 +124,7 @@ public class ArtifactWaypoint {
|
||||
*
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
private ArtifactWaypoint(BlackboardArtifact artifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
|
||||
private Waypoint(BlackboardArtifact artifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
|
||||
this(artifact,
|
||||
getLabelFromArtifact(attributeMap),
|
||||
attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME) != null ? attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME).getValueLong() : null,
|
||||
@ -207,7 +207,7 @@ public class ArtifactWaypoint {
|
||||
*
|
||||
* @return A List of waypoint properties
|
||||
*/
|
||||
public List<ArtifactWaypoint.Property> getOtherProperties() {
|
||||
public List<Waypoint.Property> getOtherProperties() {
|
||||
return immutablePropertiesList;
|
||||
}
|
||||
|
||||
@ -276,8 +276,8 @@ public class ArtifactWaypoint {
|
||||
*
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
public static List<ArtifactWaypoint> getAllWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
List<ArtifactWaypoint> points = new ArrayList<>();
|
||||
public static List<Waypoint> getAllWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
List<Waypoint> points = new ArrayList<>();
|
||||
|
||||
points.addAll(getTrackpointWaypoints(skCase));
|
||||
points.addAll(getEXIFWaypoints(skCase));
|
||||
@ -297,7 +297,7 @@ public class ArtifactWaypoint {
|
||||
*
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
public static List<ArtifactWaypoint> getTrackpointWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
public static List<Waypoint> getTrackpointWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
List<BlackboardArtifact> artifacts = null;
|
||||
try {
|
||||
artifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT);
|
||||
@ -305,10 +305,10 @@ public class ArtifactWaypoint {
|
||||
throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_TRACKPOINT", ex);
|
||||
}
|
||||
|
||||
List<ArtifactWaypoint> points = new ArrayList<>();
|
||||
List<Waypoint> points = new ArrayList<>();
|
||||
for (BlackboardArtifact artifact : artifacts) {
|
||||
try {
|
||||
ArtifactWaypoint point = new TrackpointWaypoint(artifact);
|
||||
Waypoint point = new TrackpointWaypoint(artifact);
|
||||
points.add(point);
|
||||
} catch (GeoLocationDataException ex) {
|
||||
logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_TRACKPOINT artifactID: %d", artifact.getArtifactID()));
|
||||
@ -326,7 +326,7 @@ public class ArtifactWaypoint {
|
||||
*
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
static public List<ArtifactWaypoint> getEXIFWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
static public List<Waypoint> getEXIFWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
List<BlackboardArtifact> artifacts = null;
|
||||
try {
|
||||
artifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF);
|
||||
@ -334,11 +334,11 @@ public class ArtifactWaypoint {
|
||||
throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_LAST_KNOWN_LOCATION", ex);
|
||||
}
|
||||
|
||||
List<ArtifactWaypoint> points = new ArrayList<>();
|
||||
List<Waypoint> points = new ArrayList<>();
|
||||
if (artifacts != null) {
|
||||
for (BlackboardArtifact artifact : artifacts) {
|
||||
try {
|
||||
ArtifactWaypoint point = new EXIFWaypoint(artifact);
|
||||
Waypoint point = new EXIFWaypoint(artifact);
|
||||
points.add(point);
|
||||
} catch (GeoLocationDataException ex) {
|
||||
// I am a little relucant to log this error because I suspect
|
||||
@ -359,7 +359,7 @@ public class ArtifactWaypoint {
|
||||
*
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
public static List<ArtifactWaypoint> getSearchWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
public static List<Waypoint> getSearchWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
List<BlackboardArtifact> artifacts = null;
|
||||
try {
|
||||
artifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH);
|
||||
@ -367,11 +367,11 @@ public class ArtifactWaypoint {
|
||||
throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_SEARCH", ex);
|
||||
}
|
||||
|
||||
List<ArtifactWaypoint> points = new ArrayList<>();
|
||||
List<Waypoint> points = new ArrayList<>();
|
||||
if (artifacts != null) {
|
||||
for (BlackboardArtifact artifact : artifacts) {
|
||||
try {
|
||||
ArtifactWaypoint point = new SearchWaypoint(artifact);
|
||||
Waypoint point = new SearchWaypoint(artifact);
|
||||
points.add(point);
|
||||
} catch (GeoLocationDataException ex) {
|
||||
logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_SEARCH artifactID: %d", artifact.getArtifactID()));
|
||||
@ -390,7 +390,7 @@ public class ArtifactWaypoint {
|
||||
*
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
public static List<ArtifactWaypoint> getLastKnownWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
public static List<Waypoint> getLastKnownWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
List<BlackboardArtifact> artifacts = null;
|
||||
try {
|
||||
artifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION);
|
||||
@ -398,11 +398,11 @@ public class ArtifactWaypoint {
|
||||
throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_LAST_KNOWN_LOCATION", ex);
|
||||
}
|
||||
|
||||
List<ArtifactWaypoint> points = new ArrayList<>();
|
||||
List<Waypoint> points = new ArrayList<>();
|
||||
if (artifacts != null) {
|
||||
for (BlackboardArtifact artifact : artifacts) {
|
||||
try {
|
||||
ArtifactWaypoint point = new LastKnownWaypoint(artifact);
|
||||
Waypoint point = new LastKnownWaypoint(artifact);
|
||||
points.add(point);
|
||||
} catch (GeoLocationDataException ex) {
|
||||
logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_LAST_KNOWN_LOCATION artifactID: %d", artifact.getArtifactID()));
|
||||
@ -421,7 +421,7 @@ public class ArtifactWaypoint {
|
||||
*
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
public static List<ArtifactWaypoint> getBookmarkWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
public static List<Waypoint> getBookmarkWaypoints(SleuthkitCase skCase) throws GeoLocationDataException {
|
||||
List<BlackboardArtifact> artifacts = null;
|
||||
try {
|
||||
artifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK);
|
||||
@ -429,11 +429,11 @@ public class ArtifactWaypoint {
|
||||
throw new GeoLocationDataException("Unable to get artifacts for type: TSK_GPS_BOOKMARK", ex);
|
||||
}
|
||||
|
||||
List<ArtifactWaypoint> points = new ArrayList<>();
|
||||
List<Waypoint> points = new ArrayList<>();
|
||||
if (artifacts != null) {
|
||||
for (BlackboardArtifact artifact : artifacts) {
|
||||
try {
|
||||
ArtifactWaypoint point = new ArtifactWaypoint(artifact);
|
||||
Waypoint point = new Waypoint(artifact);
|
||||
points.add(point);
|
||||
} catch (GeoLocationDataException ex) {
|
||||
logger.log(Level.WARNING, String.format("No longitude or latitude available for TSK_GPS_BOOKMARK artifactID: %d", artifact.getArtifactID()));
|
||||
@ -454,8 +454,8 @@ public class ArtifactWaypoint {
|
||||
*
|
||||
* @throws GeoLocationDataException
|
||||
*/
|
||||
static public List<ArtifactWaypoint.Property> createGeolocationProperties(Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
|
||||
List<ArtifactWaypoint.Property> list = new ArrayList<>();
|
||||
static public List<Waypoint.Property> createGeolocationProperties(Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
|
||||
List<Waypoint.Property> list = new ArrayList<>();
|
||||
|
||||
Set<BlackboardAttribute.ATTRIBUTE_TYPE> keys = new HashSet<>(attributeMap.keySet());
|
||||
|
||||
@ -467,7 +467,7 @@ public class ArtifactWaypoint {
|
||||
String key = type.getDisplayName();
|
||||
String value = attributeMap.get(type).getDisplayString();
|
||||
|
||||
list.add(new ArtifactWaypoint.Property(key, value));
|
||||
list.add(new Waypoint.Property(key, value));
|
||||
}
|
||||
return list;
|
||||
}
|
@ -730,10 +730,15 @@ class KMLReport implements GeneralReportModule {
|
||||
*
|
||||
* @param route
|
||||
*
|
||||
* @return
|
||||
* @return A HTML formatted list of the Route attributes
|
||||
*/
|
||||
<<<<<<< HEAD
|
||||
private String getFormattedDetails(Route route) {
|
||||
List<ArtifactWaypoint> points = route.getRoute();
|
||||
=======
|
||||
private String getFormattedDetails(Route route) {
|
||||
List<Waypoint> points = route.getRoute();
|
||||
>>>>>>> geolocation-datamodel-refactoring
|
||||
StringBuilder result = new StringBuilder(); //NON-NLS
|
||||
|
||||
result.append(String.format("<h3>%s</h3>", Bundle.Route_Details_Header()))
|
||||
@ -765,8 +770,13 @@ class KMLReport implements GeneralReportModule {
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
List<ArtifactWaypoint.Property> list = route.getOtherProperties();
|
||||
for(ArtifactWaypoint.Property prop: list) {
|
||||
=======
|
||||
List<Waypoint.Property> list = route.getOtherProperties();
|
||||
for(Waypoint.Property prop: list) {
|
||||
>>>>>>> geolocation-datamodel-refactoring
|
||||
String value = prop.getValue();
|
||||
if(value != null && !value.isEmpty()) {
|
||||
result.append(formatAttribute(prop.getDisplayName(), value));
|
||||
|
@ -768,6 +768,7 @@ public class PortableCaseReportModule implements ReportModule {
|
||||
oldAttr.getValueLong()));
|
||||
break;
|
||||
case STRING:
|
||||
case JSON:
|
||||
newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
|
||||
oldAttr.getValueString()));
|
||||
break;
|
||||
|
@ -50,6 +50,8 @@ final class CustomArtifactType {
|
||||
private static final String BYTES_ATTR_DISPLAY_NAME = "Custom Bytes";
|
||||
private static final String STRING_ATTR_TYPE_NAME = "CUSTOM_STRING_ATTRIBUTE";
|
||||
private static final String STRING_ATTR_DISPLAY_NAME = "Custom String";
|
||||
private static final String JSON_ATTR_TYPE_NAME = "CUSTOM_JSON_ATTRIBUTE";
|
||||
private static final String JSON_ATTR_DISPLAY_NAME = "Custom Json";
|
||||
private static BlackboardArtifact.Type artifactType;
|
||||
private static BlackboardAttribute.Type intAttrType;
|
||||
private static BlackboardAttribute.Type doubleAttrType;
|
||||
@ -57,6 +59,7 @@ final class CustomArtifactType {
|
||||
private static BlackboardAttribute.Type dateTimeAttrType;
|
||||
private static BlackboardAttribute.Type bytesAttrType;
|
||||
private static BlackboardAttribute.Type stringAttrType;
|
||||
private static BlackboardAttribute.Type jsonAttrType;
|
||||
|
||||
/**
|
||||
* Adds the custom artifact type, with its associated custom attribute
|
||||
@ -73,6 +76,7 @@ final class CustomArtifactType {
|
||||
dateTimeAttrType = blackboard.getOrAddAttributeType(DATETIME_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME, DATETIME_ATTR_DISPLAY_NAME);
|
||||
bytesAttrType = blackboard.getOrAddAttributeType(BYTES_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE, BYTES_ATTR_DISPLAY_NAME);
|
||||
stringAttrType = blackboard.getOrAddAttributeType(STRING_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, STRING_ATTR_DISPLAY_NAME);
|
||||
jsonAttrType = blackboard.getOrAddAttributeType(JSON_ATTR_TYPE_NAME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON, JSON_ATTR_DISPLAY_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,6 +97,7 @@ final class CustomArtifactType {
|
||||
attributes.add(new BlackboardAttribute(dateTimeAttrType, MODULE_NAME, 60L));
|
||||
attributes.add(new BlackboardAttribute(bytesAttrType, MODULE_NAME, DatatypeConverter.parseHexBinary("ABCD")));
|
||||
attributes.add(new BlackboardAttribute(stringAttrType, MODULE_NAME, "Zero"));
|
||||
attributes.add(new BlackboardAttribute(jsonAttrType, MODULE_NAME, "{\"fruit\": \"Apple\",\"size\": \"Large\",\"color\": \"Red\"}"));
|
||||
artifact.addAttributes(attributes);
|
||||
|
||||
/*
|
||||
|
@ -244,6 +244,8 @@ public final class FileExporterSettingsPanel extends JPanel {
|
||||
comboBoxValueType.addItem(BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING.getLabel());
|
||||
comboBoxValueType.addItem(BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME.getLabel());
|
||||
comboBoxValueType.addItem(BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE.getLabel());
|
||||
comboBoxValueType.addItem(BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON.getLabel());
|
||||
|
||||
comboBoxValueType.addItem(UNSET);
|
||||
|
||||
load();
|
||||
|
@ -45,6 +45,7 @@ from org.sleuthkit.datamodel import Account
|
||||
from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper
|
||||
from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus
|
||||
from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection
|
||||
from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CallMediaType
|
||||
|
||||
import json
|
||||
import traceback
|
||||
@ -181,15 +182,242 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer):
|
||||
contactsDb.close()
|
||||
|
||||
|
||||
|
||||
## Adds a recipient to given list
|
||||
def addRecipientToList(self, user_key, recipientList):
|
||||
## Extracts recipeint id from 'user_key' column and adds recipient to given list,
|
||||
## if the recipeint id is not the same as sender id
|
||||
def addRecipientToList(self, user_key, senderId, recipientList):
|
||||
if user_key is not None:
|
||||
recipientId = user_key.replace('FACEBOOK:', '')
|
||||
recipientList.append(recipientId)
|
||||
recipientId = user_key.replace('FACEBOOK:', '')
|
||||
if recipientId != senderId:
|
||||
recipientList.append(recipientId)
|
||||
|
||||
|
||||
## Extracts sender id from the json in 'sender' column.
|
||||
def getSenderIdFromJson(self, senderJsonStr):
|
||||
senderId = None;
|
||||
if senderJsonStr is not None:
|
||||
sender_dict = json.loads(senderJsonStr)
|
||||
senderId = sender_dict['user_key']
|
||||
senderId = senderId.replace('FACEBOOK:', '')
|
||||
|
||||
## Analyze messages
|
||||
def analyzeMessages(self, dataSource, fileManager, context):
|
||||
return senderId
|
||||
|
||||
## determines communication direction by comparing senderId with selfAccountId
|
||||
def deduceDirectionFromSenderId(self, senderId):
|
||||
direction = CommunicationDirection.UNKNOWN
|
||||
if senderId is not None:
|
||||
if senderId == self.selfAccountId:
|
||||
direction = CommunicationDirection.OUTGOING
|
||||
else:
|
||||
direction = CommunicationDirection.INCOMING
|
||||
return direction
|
||||
|
||||
## Analyzes messages
|
||||
def analyzeMessages(self, threadsDb, threadsDBHelper):
|
||||
try:
|
||||
|
||||
## Messages are found in the messages table.
|
||||
## This query filters messages by msg_type to only get actual user created conversation messages (msg_type 0).
|
||||
## The participant ids can be found in the thread_participants table.
|
||||
## Participant names are found in thread_users table.
|
||||
## Joining these tables produces multiple rows per message, one row for each recipient.
|
||||
## The result set is processed to collect the multiple recipients for a given message.
|
||||
sqlString = """
|
||||
SELECT msg_id, text, sender, timestamp_ms, msg_type, messages.thread_key as thread_key,
|
||||
snippet, thread_participants.user_key as user_key, thread_users.name as name
|
||||
FROM messages
|
||||
JOIN thread_participants ON messages.thread_key = thread_participants.thread_key
|
||||
JOIN thread_users ON thread_participants.user_key = thread_users.user_key
|
||||
WHERE msg_type = 0
|
||||
ORDER BY msg_id
|
||||
"""
|
||||
|
||||
messagesResultSet = threadsDb.runQuery(sqlString)
|
||||
if messagesResultSet is not None:
|
||||
oldMsgId = None
|
||||
|
||||
direction = CommunicationDirection.UNKNOWN
|
||||
fromId = None
|
||||
recipientIdsList = None
|
||||
timeStamp = -1
|
||||
msgText = ""
|
||||
threadId = ""
|
||||
|
||||
while messagesResultSet.next():
|
||||
msgId = messagesResultSet.getString("msg_id")
|
||||
|
||||
# new msg begins when msgId changes
|
||||
if msgId != oldMsgId:
|
||||
# Create message artifact with collected attributes
|
||||
if oldMsgId is not None:
|
||||
messageArtifact = threadsDBHelper.addMessage(
|
||||
self._MESSAGE_TYPE,
|
||||
direction,
|
||||
fromId,
|
||||
recipientIdsList,
|
||||
timeStamp,
|
||||
MessageReadStatus.UNKNOWN,
|
||||
"", # subject
|
||||
msgText,
|
||||
threadId)
|
||||
|
||||
oldMsgId = msgId
|
||||
|
||||
# New message - collect all attributes
|
||||
recipientIdsList = []
|
||||
|
||||
## get sender id by parsing JSON in sender column
|
||||
fromId = self.getSenderIdFromJson(messagesResultSet.getString("sender"))
|
||||
direction = self.deduceDirectionFromSenderId(fromId)
|
||||
|
||||
# Get recipient and add to list
|
||||
self.addRecipientToList(messagesResultSet.getString("user_key"), fromId,
|
||||
recipientIdsList)
|
||||
|
||||
timeStamp = messagesResultSet.getLong("timestamp_ms") / 1000
|
||||
|
||||
# Get msg text
|
||||
# Sometimes there may not be an explict msg text,
|
||||
# but an app generated snippet instead
|
||||
msgText = messagesResultSet.getString("text")
|
||||
if not msgText:
|
||||
msgText = messagesResultSet.getString("snippet")
|
||||
|
||||
# TBD: get attachment
|
||||
|
||||
threadId = messagesResultSet.getString("thread_key")
|
||||
|
||||
else: # same msgId as last, just collect recipient from current row
|
||||
self.addRecipientToList(messagesResultSet.getString("user_key"), fromId,
|
||||
recipientIdsList)
|
||||
|
||||
|
||||
# at the end of the loop, add last message
|
||||
messageArtifact = threadsDBHelper.addMessage(
|
||||
self._MESSAGE_TYPE,
|
||||
direction,
|
||||
fromId,
|
||||
recipientIdsList,
|
||||
timeStamp,
|
||||
MessageReadStatus.UNKNOWN,
|
||||
"", # subject
|
||||
msgText,
|
||||
threadId)
|
||||
|
||||
except SQLException as ex:
|
||||
self._logger.log(Level.WARNING, "Error processing query result for FB Messenger messages.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except TskCoreException as ex:
|
||||
self._logger.log(Level.SEVERE, "Failed to add FB Messenger message artifacts.", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except BlackboardException as ex:
|
||||
self._logger.log(Level.WARNING, "Failed to post artifacts.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
|
||||
## Analyzes call logs
|
||||
def analyzeCallLogs(self, threadsDb, threadsDBHelper):
|
||||
try:
|
||||
|
||||
## Call logs are found in the messages table.
|
||||
## msg_type indicates type of call:
|
||||
## 9: one to one calls
|
||||
## 203: group call
|
||||
## 1-to-1 calls only have a call_ended record.
|
||||
## group calls have a call_started_record as well as call_ended recorded, with *different* message ids.
|
||||
## all the data we need can be found in the call_ended record.
|
||||
|
||||
sqlString = """
|
||||
SELECT msg_id, text, sender, timestamp_ms, msg_type, admin_text_thread_rtc_event,
|
||||
generic_admin_message_extensible_data,
|
||||
messages.thread_key as thread_key,
|
||||
thread_participants.user_key as user_key,
|
||||
thread_users.name as name
|
||||
FROM messages
|
||||
JOIN thread_participants ON messages.thread_key = thread_participants.thread_key
|
||||
JOIN thread_users ON thread_participants.user_key = thread_users.user_key
|
||||
WHERE msg_type = 9 OR (msg_type = 203 AND admin_text_thread_rtc_event = 'group_call_ended')
|
||||
ORDER BY msg_id
|
||||
"""
|
||||
|
||||
messagesResultSet = threadsDb.runQuery(sqlString)
|
||||
if messagesResultSet is not None:
|
||||
oldMsgId = None
|
||||
|
||||
direction = CommunicationDirection.UNKNOWN
|
||||
callerId = None
|
||||
calleeIdsList = None
|
||||
startTimeStamp = -1
|
||||
endTimeStamp = -1
|
||||
duration = 0
|
||||
mediaType = CallMediaType.AUDIO
|
||||
|
||||
while messagesResultSet.next():
|
||||
msgId = messagesResultSet.getString("msg_id")
|
||||
|
||||
# new call begins when msgId changes
|
||||
if msgId != oldMsgId:
|
||||
# Create call log artifact with collected attributes
|
||||
if oldMsgId is not None:
|
||||
messageArtifact = threadsDBHelper.addCalllog(
|
||||
direction,
|
||||
callerId,
|
||||
calleeIdsList,
|
||||
startTimeStamp,
|
||||
endTimeStamp,
|
||||
mediaType )
|
||||
|
||||
oldMsgId = msgId
|
||||
|
||||
# New message - collect all attributes
|
||||
calleeIdsList = []
|
||||
|
||||
## get caller id by parsing JSON in sender column
|
||||
callerId = self.getSenderIdFromJson(messagesResultSet.getString("sender"))
|
||||
direction = self.deduceDirectionFromSenderId(callerId)
|
||||
|
||||
# Get recipient and add to list
|
||||
self.addRecipientToList(messagesResultSet.getString("user_key"), callerId,
|
||||
calleeIdsList)
|
||||
|
||||
# the timestamp from call ended msg is used as end timestamp
|
||||
endTimeStamp = messagesResultSet.getLong("timestamp_ms") / 1000
|
||||
|
||||
# parse the generic_admin_message_extensible_data JSON to extract the duration and video fields
|
||||
adminDataJsonStr = messagesResultSet.getString("generic_admin_message_extensible_data")
|
||||
if adminDataJsonStr is not None:
|
||||
adminData_dict = json.loads(adminDataJsonStr)
|
||||
duration = adminData_dict['call_duration'] # call duration in seconds
|
||||
isVideo = adminData_dict['video']
|
||||
if isVideo:
|
||||
mediaType = CallMediaType.VIDEO
|
||||
|
||||
startTimeStamp = endTimeStamp - duration
|
||||
|
||||
else: # same msgId as last, just collect callee from current row
|
||||
self.addRecipientToList(messagesResultSet.getString("user_key"), callerId,
|
||||
calleeIdsList)
|
||||
|
||||
# at the end of the loop, add last message
|
||||
messageArtifact = threadsDBHelper.addCalllog(
|
||||
direction,
|
||||
callerId,
|
||||
calleeIdsList,
|
||||
startTimeStamp,
|
||||
endTimeStamp,
|
||||
mediaType )
|
||||
|
||||
except SQLException as ex:
|
||||
self._logger.log(Level.WARNING, "Error processing query result for FB Messenger call logs.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except TskCoreException as ex:
|
||||
self._logger.log(Level.SEVERE, "Failed to add FB Messenger call log artifacts.", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except BlackboardException as ex:
|
||||
self._logger.log(Level.WARNING, "Failed to post FB Messenger call log artifacts.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
|
||||
|
||||
## Analyze messages and call log threads
|
||||
def analyzeMessagesAndCallLogs(self, dataSource, fileManager, context):
|
||||
threadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "threads_db2", True, self._FB_MESSENGER_PACKAGE_NAME)
|
||||
for threadsDb in threadsDbs:
|
||||
try:
|
||||
@ -202,113 +430,12 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer):
|
||||
self._MODULE_NAME, threadsDb.getDBFile(),
|
||||
Account.Type.FACEBOOK)
|
||||
|
||||
## Messages are found in the messages table.
|
||||
## This query filters messages by msg_type to only get actual user created conversation messages (msg_type 0).
|
||||
## The participant ids can be found in the thread_participants table.
|
||||
## Participant names are found in thread_users table.
|
||||
## Joining these tables produces multiple rows per message, one row for each recipient.
|
||||
## The result set is processed to collect the multiple recipients for a given message.
|
||||
sqlString = """
|
||||
SELECT msg_id, text, sender, timestamp_ms, msg_type, messages.thread_key as thread_key,
|
||||
snippet, thread_participants.user_key as user_key, thread_users.name as name
|
||||
FROM messages
|
||||
JOIN thread_participants ON messages.thread_key = thread_participants.thread_key
|
||||
JOIN thread_users ON thread_participants.user_key = thread_users.user_key
|
||||
WHERE msg_type = 0
|
||||
ORDER BY msg_id
|
||||
"""
|
||||
|
||||
messagesResultSet = threadsDb.runQuery(sqlString)
|
||||
if messagesResultSet is not None:
|
||||
oldMsgId = None
|
||||
|
||||
direction = CommunicationDirection.UNKNOWN
|
||||
fromId = None
|
||||
recipientIdsList = None
|
||||
timeStamp = -1
|
||||
msgText = ""
|
||||
threadId = ""
|
||||
|
||||
while messagesResultSet.next():
|
||||
msgId = messagesResultSet.getString("msg_id")
|
||||
|
||||
# new msg begins when msgId changes
|
||||
if msgId != oldMsgId:
|
||||
# Create message artifact with collected attributes
|
||||
if oldMsgId is not None:
|
||||
messageArtifact = threadsDBHelper.addMessage(
|
||||
self._MESSAGE_TYPE,
|
||||
direction,
|
||||
fromId,
|
||||
recipientIdsList,
|
||||
timeStamp,
|
||||
MessageReadStatus.UNKNOWN,
|
||||
"", # subject
|
||||
msgText,
|
||||
threadId)
|
||||
|
||||
oldMsgId = msgId
|
||||
|
||||
# New message - collect all attributes
|
||||
recipientIdsList = []
|
||||
|
||||
## get sender id by parsing JSON in sender column
|
||||
senderJsonStr = messagesResultSet.getString("sender")
|
||||
if senderJsonStr is not None:
|
||||
sender_dict = json.loads(senderJsonStr)
|
||||
senderId = sender_dict['user_key']
|
||||
senderId = senderId.replace('FACEBOOK:', '')
|
||||
senderName = sender_dict['name']
|
||||
fromId = senderId
|
||||
if senderId == self.selfAccountId:
|
||||
direction = CommunicationDirection.OUTGOING
|
||||
else:
|
||||
direction = CommunicationDirection.INCOMING
|
||||
|
||||
|
||||
# Get recipient and add to list
|
||||
self.addRecipientToList(messagesResultSet.getString("user_key"),
|
||||
recipientIdsList)
|
||||
|
||||
timeStamp = messagesResultSet.getLong("timestamp_ms") / 1000
|
||||
|
||||
# Get msg text
|
||||
# Sometimes there may not be an explict msg text,
|
||||
# but an app generated snippet instead
|
||||
msgText = messagesResultSet.getString("text")
|
||||
if not msgText:
|
||||
msgText = messagesResultSet.getString("snippet")
|
||||
|
||||
# TBD: get attachment
|
||||
|
||||
threadId = messagesResultSet.getString("thread_key")
|
||||
|
||||
else: # same msgId as last, just collect recipient from current row
|
||||
self.addRecipientToList(messagesResultSet.getString("user_key"),
|
||||
recipientIdsList)
|
||||
|
||||
|
||||
# at the end of the loop, add last message
|
||||
messageArtifact = threadsDBHelper.addMessage(
|
||||
self._MESSAGE_TYPE,
|
||||
direction,
|
||||
fromId,
|
||||
recipientIdsList,
|
||||
timeStamp,
|
||||
MessageReadStatus.UNKNOWN,
|
||||
"", # subject
|
||||
msgText,
|
||||
threadId)
|
||||
self.analyzeMessages(threadsDb, threadsDBHelper)
|
||||
self.analyzeCallLogs(threadsDb, threadsDBHelper)
|
||||
|
||||
except SQLException as ex:
|
||||
self._logger.log(Level.WARNING, "Error processing query result for FB Messenger messages.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except TskCoreException as ex:
|
||||
self._logger.log(Level.SEVERE, "Failed to add FB Messenger message artifacts.", ex)
|
||||
self._logger.log(Level.SEVERE, "Failed to to create CommunicationArtifactsHelper for FB Messenger.", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except BlackboardException as ex:
|
||||
self._logger.log(Level.WARNING, "Failed to post artifacts.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
finally:
|
||||
threadsDb.close()
|
||||
|
||||
@ -321,6 +448,6 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer):
|
||||
return
|
||||
|
||||
self.analyzeContacts(dataSource, fileManager, context)
|
||||
self.analyzeMessages(dataSource, fileManager, context)
|
||||
self.analyzeMessagesAndCallLogs(dataSource, fileManager, context)
|
||||
|
||||
|
||||
|
@ -43,10 +43,14 @@ from org.sleuthkit.datamodel import Content
|
||||
from org.sleuthkit.datamodel import TskCoreException
|
||||
from org.sleuthkit.datamodel.Blackboard import BlackboardException
|
||||
from org.sleuthkit.datamodel import Account
|
||||
from org.sleuthkit.datamodel.blackboardutils import FileAttachment
|
||||
from org.sleuthkit.datamodel.blackboardutils import URLAttachment
|
||||
from org.sleuthkit.datamodel.blackboardutils import MessageAttachments
|
||||
from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper
|
||||
from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus
|
||||
from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection
|
||||
|
||||
import json
|
||||
import traceback
|
||||
import general
|
||||
|
||||
@ -66,6 +70,8 @@ class IMOAnalyzer(general.AndroidComponentAnalyzer):
|
||||
-- A messages table which stores the message details
|
||||
--- sender/receiver buid, timestamp, message_type (1: incoming, 0: outgoing), message_read...
|
||||
--- 'imdata' column stores a json structure with all the message details, including attachments
|
||||
---- attachment file path may be specified in local_path or original_path. Original path, if available is a better candidate.
|
||||
---- For sent files, files seem to get uploaded to IMO Servers. There is no URL available in the imdata though.
|
||||
|
||||
"""
|
||||
|
||||
@ -156,7 +162,7 @@ class IMOAnalyzer(general.AndroidComponentAnalyzer):
|
||||
msgReadStatus = MessageReadStatus.UNKNOWN
|
||||
|
||||
timeStamp = messagesResultSet.getLong("timestamp") / 1000000000
|
||||
|
||||
msgBody = messagesResultSet.getString("last_message")
|
||||
|
||||
messageArtifact = friendsDBHelper.addMessage(
|
||||
self._MESSAGE_TYPE,
|
||||
@ -166,12 +172,34 @@ class IMOAnalyzer(general.AndroidComponentAnalyzer):
|
||||
timeStamp,
|
||||
msgReadStatus,
|
||||
"", # subject
|
||||
messagesResultSet.getString("last_message"),
|
||||
msgBody,
|
||||
"") # thread id
|
||||
|
||||
# TBD: parse the imdata JSON structure to figure out if there is an attachment.
|
||||
# If one exists, add the attachment as a derived file and a child of the message artifact.
|
||||
|
||||
|
||||
# Parse the imdata JSON structure to check if there is an attachment.
|
||||
# If one exists, create an attachment and add to the message.
|
||||
fileAttachments = ArrayList()
|
||||
urlAttachments = ArrayList()
|
||||
|
||||
imdataJsonStr = messagesResultSet.getString("imdata")
|
||||
if imdataJsonStr is not None:
|
||||
imdata_dict = json.loads(imdataJsonStr)
|
||||
|
||||
# set to none if the key doesn't exist in the dict
|
||||
attachmentOriginalPath = imdata_dict.get('original_path', None)
|
||||
attachmentLocalPath = imdata_dict.get('local_path', None)
|
||||
if attachmentOriginalPath:
|
||||
attachmentPath = attachmentOriginalPath
|
||||
else:
|
||||
attachmentPath = attachmentLocalPath
|
||||
|
||||
if attachmentPath:
|
||||
# Create a file attachment with given path
|
||||
fileAttachment = FileAttachment(current_case.getSleuthkitCase(), friendsDb.getDBFile().getDataSource(), attachmentPath)
|
||||
fileAttachments.add(fileAttachment)
|
||||
|
||||
msgAttachments = MessageAttachments(fileAttachments, [])
|
||||
attachmentArtifact = friendsDBHelper.addAttachments(messageArtifact, msgAttachments)
|
||||
|
||||
except SQLException as ex:
|
||||
self._logger.log(Level.WARNING, "Error processing query result for IMO friends", ex)
|
||||
|
12
travis_build.sh
Normal file
12
travis_build.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
echo "Building TSK..."
|
||||
cd sleuthkit/sleuthkit
|
||||
./bootstrap && configure --prefix=/usr && make
|
||||
pushd bindings/java && ant -q dist-PostgreSQL && popd
|
||||
|
||||
echo "Building Autopsy..." && echo -en 'travis_fold:start:script.build\\r'
|
||||
cd $TRAVIS_BUILD_DIR/
|
||||
ant build
|
||||
echo -en 'travis_fold:end:script.build\\r'
|
Loading…
x
Reference in New Issue
Block a user