diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties
index 80e8cfd4d4..c7ceb01a4a 100644
--- a/Core/nbproject/project.properties
+++ b/Core/nbproject/project.properties
@@ -78,7 +78,7 @@ file.reference.javax.ws.rs-api-2.0.1.jar=release/modules/ext/javax.ws.rs-api-2.0
file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar
file.reference.cxf-rt-frontend-jaxrs-3.0.16.jar=release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar
file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-transports-http-3.0.16.jar
-file.reference.sleuthkit-postgresql-4.8.0.jar=release/modules/ext/sleuthkit-postgresql-4.8.0.jar
+file.reference.sleuthkit-postgresql-4.9.0.jar=release/modules/ext/sleuthkit-postgresql-4.9.0.jar
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
file.reference.curator-framework-2.8.0.jar=release/modules/ext/curator-framework-2.8.0.jar
file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0.jar
diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml
index 02d37221a7..4aa97960f3 100644
--- a/Core/nbproject/project.xml
+++ b/Core/nbproject/project.xml
@@ -532,8 +532,8 @@
release/modules/ext/google-http-client-1.29.0.jar
- ext/sleuthkit-postgresql-4.8.0.jar
- release/modules/ext/sleuthkit-postgresql-4.8.0.jar
+ ext/sleuthkit-postgresql-4.9.0.jar
+ release/modules/ext/sleuthkit-postgresql-4.9.0.jar
ext/bcpkix-jdk15on-1.60.jar
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java
index 3d610890da..a64809a07d 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseCloseAction.java
@@ -50,7 +50,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.casemodule.CaseCloseAction")
@ActionRegistration(displayName = "#CTL_CaseCloseAct", lazy = false)
@ActionReferences(value = {
- @ActionReference(path = "Toolbars/Case", position = 106)})
+ @ActionReference(path = "Toolbars/Case", position = 107)})
public final class CaseCloseAction extends CallableSystemAction implements Presenter.Toolbar {
private static final long serialVersionUID = 1L;
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java
index ee49b19c61..71c6b41f86 100755
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java
@@ -284,9 +284,13 @@ public class CorrelationAttributeUtil {
// Get the account type from the artifact
BlackboardAttribute accountTypeAttribute = acctArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE));
String accountTypeStr = accountTypeAttribute.getValueString();
-
+
+ // @@TODO Vik-6136: CR currently does not know of custom account types.
+ // Ensure there is a predefined account type for this account.
+ Account.Type predefinedAccountType = Account.Type.PREDEFINED_ACCOUNT_TYPES.stream().filter(type -> type.getTypeName().equalsIgnoreCase(accountTypeStr)).findAny().orElse(null);
+
// do not create any correlation attribute instance for a Device account
- if (Account.Type.DEVICE.getTypeName().equalsIgnoreCase(accountTypeStr) == false) {
+ if (Account.Type.DEVICE.getTypeName().equalsIgnoreCase(accountTypeStr) == false && predefinedAccountType != null) {
// Get the corresponding CentralRepoAccountType from the database.
CentralRepoAccountType crAccountType = CentralRepository.getInstance().getAccountTypeByName(accountTypeStr);
diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java
index f36f8ab520..5eb521f3d5 100644
--- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java
+++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java
@@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.commonpropertiessearch;
import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -119,6 +120,13 @@ public final class InterCasePanel extends javax.swing.JPanel {
this.correlationTypeFilters = new HashMap<>();
try {
List types = CentralRepository.getInstance().getDefinedCorrelationTypes();
+ Collections.sort(types, new Comparator() {
+ //The types should be sorted so that the File type is the first item in the combo box.
+ @Override
+ public int compare(CorrelationAttributeInstance.Type type1, CorrelationAttributeInstance.Type type2) {
+ return Integer.compare(type1.getId(), type2.getId());
+ }
+ });
for (CorrelationAttributeInstance.Type type : types) {
correlationTypeFilters.put(type.getDisplayName(), type);
this.correlationTypeComboBox.addItem(type.getDisplayName());
@@ -295,7 +303,7 @@ public final class InterCasePanel extends javax.swing.JPanel {
private void correlationTypeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_correlationTypeComboBoxActionPerformed
- boolean enableFileTypesFilter = this.correlationTypeComboBox.getSelectedItem().equals("Files");
+ boolean enableFileTypesFilter = this.correlationTypeComboBox.getSelectedItem().equals("Files");
categoriesLabel.setEnabled(enableFileTypesFilter);
allFileCategoriesRadioButton.setEnabled(enableFileTypesFilter);
selectedFileCategoriesButton.setEnabled(enableFileTypesFilter);
@@ -329,8 +337,8 @@ public final class InterCasePanel extends javax.swing.JPanel {
// End of variables declaration//GEN-END:variables
/**
- * Get the map of cases which was used to populate the combo box on
- * this panel.
+ * Get the map of cases which was used to populate the combo box on this
+ * panel.
*
* @return an unmodifiable copy of the map of cases
*/
@@ -339,8 +347,8 @@ public final class InterCasePanel extends javax.swing.JPanel {
}
/**
- * Set the datamodel for the combo box which displays the cases in
- * the central repository
+ * Set the datamodel for the combo box which displays the cases in the
+ * central repository
*
* @param dataSourceComboBoxModel the DataSourceComboBoxModel to use
*/
diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java
index 67e0366a9b..588e474303 100755
--- a/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java
+++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java
@@ -28,6 +28,7 @@ import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
@@ -45,7 +46,6 @@ final class CorrelationCaseChildNodeFactory extends ChildFactory correlationTypeMap;
private final Set accounts;
/**
@@ -108,22 +108,15 @@ final class CorrelationCaseChildNodeFactory extends ChildFactory();
- List correcationTypeList = CentralRepository.getInstance().getDefinedCorrelationTypes();
- correcationTypeList.forEach((type) -> {
- correlationTypeMap.put(type.getId(), type);
- });
- }
-
- if (Account.Type.EMAIL.equals(accountType)) {
- return correlationTypeMap.get(CorrelationAttributeInstance.EMAIL_TYPE_ID);
- } else if (Account.Type.PHONE.equals(accountType)) {
- return correlationTypeMap.get(CorrelationAttributeInstance.PHONE_TYPE_ID);
- } else {
- return null;
+ private CorrelationAttributeInstance.Type getCorrelationType(Account.Type accountType) throws CentralRepoException {
+ String accountTypeStr = accountType.getTypeName();
+ if (Account.Type.DEVICE.getTypeName().equalsIgnoreCase(accountTypeStr) == false) {
+ CentralRepoAccount.CentralRepoAccountType crAccountType = CentralRepository.getInstance().getAccountTypeByName(accountTypeStr);
+ int corrTypeId = crAccountType.getCorrelationTypeId();
+ return CentralRepository.getInstance().getCorrelationTypeById(corrTypeId);
}
+
+ return null;
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java
index 5e90d83c98..38e245aec3 100755
--- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java
@@ -247,6 +247,8 @@ public class MessageViewer extends JPanel implements RelationshipsViewer {
*/
private void showMessagesPane() {
switchCard("messages");
+ Outline outline = rootTablePane.getOutlineView().getOutline();
+ outline.clearSelection();
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java
index 5832625b73..b25f83d195 100644
--- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java
+++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java
@@ -23,6 +23,10 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.io.Files;
import java.awt.Image;
import java.awt.image.BufferedImage;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Paths;
@@ -79,6 +83,9 @@ import org.sleuthkit.autopsy.textextractors.TextExtractor;
import org.sleuthkit.autopsy.textextractors.TextExtractorFactory;
import org.sleuthkit.autopsy.textsummarizer.TextSummarizer;
import org.sleuthkit.autopsy.textsummarizer.TextSummary;
+import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
+import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
+import org.sleuthkit.autopsy.texttranslation.TranslationException;
/**
* Main class to perform the file search.
@@ -304,9 +311,113 @@ class FileSearch {
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error getting children for file: " + file.getId(), ex);
}
- image = image == null ? image : image.getScaledInstance(ImageUtils.ICON_SIZE_MEDIUM, ImageUtils.ICON_SIZE_MEDIUM,
+ image = image == null ? image : image.getScaledInstance(ImageUtils.ICON_SIZE_MEDIUM, ImageUtils.ICON_SIZE_MEDIUM,
Image.SCALE_SMOOTH);
- return new TextSummary(getFirstLines(file), image, countOfImages);
+ String summaryText = null;
+ if (file.getMd5Hash() != null) {
+ try {
+ summaryText = getSavedSummary(Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(), "summaries", file.getMd5Hash() + "-default-" + PREVIEW_SIZE + "-translated.txt").toString());
+ } catch (NoCurrentCaseException ex) {
+ logger.log(Level.WARNING, "Unable to retrieve saved summary. No case is open.", ex);
+ }
+ }
+ if (StringUtils.isBlank(summaryText)) {
+ String firstLines = getFirstLines(file);
+ String translatedFirstLines = getTranslatedVersion(firstLines);
+ if (!StringUtils.isBlank(translatedFirstLines)) {
+ summaryText = translatedFirstLines;
+ if (file.getMd5Hash() != null) {
+ try {
+ saveSummary(summaryText, Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(), "summaries", file.getMd5Hash() + "-default-" + PREVIEW_SIZE + "-translated.txt").toString());
+ } catch (NoCurrentCaseException ex) {
+ logger.log(Level.WARNING, "Unable to save translated summary. No case is open.", ex);
+ }
+ }
+ } else {
+ summaryText = firstLines;
+ }
+ }
+ return new TextSummary(summaryText, image, countOfImages);
+ }
+
+ /**
+ * Provide an English version of the specified String if it is not English,
+ * translation is enabled, and it can be translated.
+ *
+ * @param documentString The String to provide an English version of.
+ *
+ * @return The English version of the provided String, or null if no
+ * translation occurred.
+ */
+ private static String getTranslatedVersion(String documentString) {
+ try {
+ TextTranslationService translatorInstance = TextTranslationService.getInstance();
+ if (translatorInstance.hasProvider()) {
+ String translatedResult = translatorInstance.translate(documentString);
+ if (translatedResult.isEmpty() == false) {
+ return translatedResult;
+ }
+ }
+ } catch (NoServiceProviderException | TranslationException ex) {
+ logger.log(Level.INFO, "Error translating string for summary", ex);
+ }
+ return null;
+ }
+
+ /**
+ * Find and load a saved summary from the case folder for the specified
+ * file.
+ *
+ * @param summarySavePath The full path for the saved summary file.
+ *
+ * @return The summary found given the specified path, null if no summary
+ * was found.
+ */
+ private static String getSavedSummary(String summarySavePath) {
+ if (summarySavePath == null) {
+ return null;
+ }
+ File savedFile = new File(summarySavePath);
+ if (savedFile.exists()) {
+ try (BufferedReader bReader = new BufferedReader(new FileReader(savedFile))) {
+ // pass the path to the file as a parameter
+ StringBuilder sBuilder = new StringBuilder();
+ String sCurrentLine = bReader.readLine();
+ while (sCurrentLine != null) {
+ sBuilder.append(sCurrentLine).append('\n');
+ sCurrentLine = bReader.readLine();
+ }
+ return sBuilder.toString();
+ } catch (IOException ingored) {
+ //summary file may not exist or may be incomplete in which case return null so a summary can be generated
+ return null; //no saved summary was able to be found
+ }
+ } else {
+ try { //if the file didn't exist make sure the parent directories exist before we move on to creating a summary
+ Files.createParentDirs(savedFile);
+ } catch (IOException ex) {
+ logger.log(Level.WARNING, "Unable to create summaries directory in case folder for file at: " + summarySavePath, ex);
+ }
+ return null; //no saved summary was able to be found
+ }
+
+ }
+
+ /**
+ * Save a summary at the specified location.
+ *
+ * @param summary The text of the summary being saved.
+ * @param summarySavePath The full path for the saved summary file.
+ */
+ private static void saveSummary(String summary, String summarySavePath) {
+ if (summarySavePath == null) {
+ return; //can't save a summary if we don't have a path
+ }
+ try (FileWriter myWriter = new FileWriter(summarySavePath)) {
+ myWriter.write(summary);
+ } catch (IOException ex) {
+ logger.log(Level.WARNING, "Unable to save summary at: " + summarySavePath, ex);
+ }
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Route.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Route.java
index 67de1e55ba..13a23b30e3 100755
--- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Route.java
+++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Route.java
@@ -2,7 +2,7 @@
*
* Autopsy Forensic Browser
*
- * Copyright 2019 Basis Technology Corp.
+ * Copyright 2019-2020 Basis Technology Corp.
* contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,9 +25,9 @@ import java.util.Map;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
-import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil;
-import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil.GeoWaypointList.GeoWaypoint;
-import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil.GeoWaypointList;
+import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
+import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil.InvalidJsonException;
+import org.sleuthkit.datamodel.blackboardutils.attributes.GeoWaypoints;
/**
* A Route represents a TSK_GPS_ROUTE artifact which has a start and end point
@@ -42,8 +42,6 @@ public class Route extends GeoPath {
// This list is not expected to change after construction so the
// constructor will take care of creating an unmodifiable List
private final List propertiesList;
-
- private static final TskGeoWaypointsUtil attributeUtil = new TskGeoWaypointsUtil();
/**
* Construct a route for the given artifact.
@@ -119,9 +117,13 @@ public class Route extends GeoPath {
}
if (attribute != null) {
- GeoWaypointList waypoints = attributeUtil.fromAttribute(attribute);
-
- for(GeoWaypoint waypoint: waypoints) {
+ GeoWaypoints waypoints;
+ try {
+ waypoints = BlackboardJsonAttrUtil.fromAttribute(attribute, GeoWaypoints.class);
+ } catch (InvalidJsonException ex) {
+ throw new GeoLocationDataException(String.format("Unable to parse waypoints in TSK_GEO_WAYPOINTS attribute (artifact object ID =%d)", artifact.getId()), ex);
+ }
+ for (GeoWaypoints.Waypoint waypoint : waypoints) {
addToPath(new Waypoint(artifact, label, null, waypoint.getLatitude(), waypoint.getLongitude(), waypoint.getAltitude(), null, attributeMap, this));
}
} else {
diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java
index 213bd6b5f5..68da242b8a 100755
--- a/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java
+++ b/Core/src/org/sleuthkit/autopsy/geolocation/datamodel/Track.java
@@ -1,5 +1,4 @@
/*
- *
* Autopsy Forensic Browser
*
* Copyright 2020 Basis Technology Corp.
@@ -26,26 +25,24 @@ import java.util.Map;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
-import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil;
-import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList;
-import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList.GeoTrackPoint;
+import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
+import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil.InvalidJsonException;
+import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints;
/**
* A GPS track with which wraps the TSK_GPS_TRACK artifact.
*/
-public final class Track extends GeoPath{
+public final class Track extends GeoPath {
private final Long startTimestamp;
private final Long endTimeStamp;
-
- private static final TskGeoTrackpointsUtil attributeUtil = new TskGeoTrackpointsUtil();
/**
* Construct a new Track for the given artifact.
- *
+ *
* @param artifact
- *
- * @throws GeoLocationDataException
+ *
+ * @throws GeoLocationDataException
*/
public Track(BlackboardArtifact artifact) throws GeoLocationDataException {
this(artifact, Waypoint.getAttributesFromArtifactAsMap(artifact));
@@ -53,49 +50,49 @@ public final class Track extends GeoPath{
/**
* Construct a Track for the given artifact and attributeMap.
- *
- * @param artifact TSK_GPD_TRACK artifact
- * @param attributeMap Map of the artifact attributes
- *
- * @throws GeoLocationDataException
+ *
+ * @param artifact TSK_GPD_TRACK artifact
+ * @param attributeMap Map of the artifact attributes
+ *
+ * @throws GeoLocationDataException
*/
private Track(BlackboardArtifact artifact, Map attributeMap) throws GeoLocationDataException {
super(artifact, getTrackName(attributeMap));
- GeoTrackPointList points = getPointsList(attributeMap);
+ GeoTrackPoints points = getPointsList(attributeMap);
buildPath(points, artifact);
startTimestamp = points.getStartTime();
endTimeStamp = points.getEndTime();
}
-
+
/**
* Returns the start time of this track.
- *
- * @return Earliest time, or null if none was available.
- * (seconds from java epoch)
+ *
+ * @return Earliest time, or null if none was available. (seconds from java
+ * epoch)
*/
public Long getStartTime() {
return startTimestamp;
}
-
+
/**
* Returns the end time of this track.
- *
- * @return Earliest timestamp, or null if none was available.
- * (seconds from java epoch)
+ *
+ * @return Earliest timestamp, or null if none was available. (seconds from
+ * java epoch)
*/
public Long getEndTime() {
return endTimeStamp;
}
/**
- * Return the name of the track from the attributeMap.
- * Track name is stored in the attribute TSK_NAME
- *
+ * Return the name of the track from the attributeMap. Track name is stored
+ * in the attribute TSK_NAME
+ *
* @param attributeMap
-
- * @return Track name or empty string if none was available.
+ *
+ * @return Track name or empty string if none was available.
*/
private static String getTrackName(Map attributeMap) {
BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
@@ -105,38 +102,41 @@ public final class Track extends GeoPath{
/**
* Create the list of TrackWaypoints from the GeoTrackPoint list.
- *
- * @param points List of GeoTrackPoints
- *
+ *
+ * @param points GeoTrackPoints object.
* @param artifact The artifact to which these points belong
- *
- * @throws GeoLocationDataException
+ *
+ * @throws GeoLocationDataException
*/
@Messages({
"# {0} - track name",
"GEOTrack_point_label_header=Trackpoint for track: {0}"
})
- private void buildPath(GeoTrackPointList points, BlackboardArtifact artifact)
- throws GeoLocationDataException {
- for(GeoTrackPoint point: points) {
+ private void buildPath(GeoTrackPoints points, BlackboardArtifact artifact) throws GeoLocationDataException {
+ for (GeoTrackPoints.TrackPoint point : points) {
addToPath(new TrackWaypoint(artifact, Bundle.GEOTrack_point_label_header(getLabel()), point));
}
}
/**
- * Returns the list of GeoTrackPoints from the attributeMap. Creates the
+ * Returns the list of GeoTrackPoints from the attributeMap. Creates the
* GeoTrackPoint list from the TSK_GEO_TRACKPOINTS attribute.
- *
+ *
* @param attributeMap Map of artifact attributes.
- *
+ *
* @return GeoTrackPoint list empty list if the attribute was not found.
+ *
+ * @throws GeoLocationDataException
*/
- private GeoTrackPointList getPointsList(Map attributeMap) {
+ private GeoTrackPoints getPointsList(Map attributeMap) throws GeoLocationDataException {
BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS);
if (attribute != null) {
- return attributeUtil.fromAttribute(attribute);
+ try {
+ return BlackboardJsonAttrUtil.fromAttribute(attribute, GeoTrackPoints.class);
+ } catch (InvalidJsonException ex) {
+ throw new GeoLocationDataException("Unable to parse track points in TSK_GEO_TRACKPOINTS attribute", ex);
+ }
}
-
return null;
}
@@ -149,16 +149,16 @@ public final class Track extends GeoPath{
/**
* Construct a TrackWaypoint.
- *
- * @param artifact the artifact to which this waypoint belongs
- *
+ *
+ * @param artifact the artifact to which this waypoint belongs
+ *
* @param pointLabel the label for the waypoint
- *
- * @param point GeoTrackPoint
- *
- * @throws GeoLocationDataException
+ *
+ * @param point GeoTrackPoint
+ *
+ * @throws GeoLocationDataException
*/
- TrackWaypoint(BlackboardArtifact artifact, String pointLabel, GeoTrackPoint point) throws GeoLocationDataException {
+ TrackWaypoint(BlackboardArtifact artifact, String pointLabel, GeoTrackPoints.TrackPoint point) throws GeoLocationDataException {
super(artifact, pointLabel,
point.getTimeStamp(),
point.getLatitude(),
@@ -172,10 +172,10 @@ public final class Track extends GeoPath{
}
/**
- * Overloaded to return a property list that is generated from
- * the GeoTrackPoint instead of an artifact.
- *
- * @return unmodifiable list of Waypoint.Property
+ * Overloaded to return a property list that is generated from the
+ * GeoTrackPoint instead of an artifact.
+ *
+ * @return unmodifiable list of Waypoint.Property
*/
@Override
public List getOtherProperties() {
@@ -184,16 +184,16 @@ public final class Track extends GeoPath{
/**
* Create a propertyList specific to GeoTrackPoints.
- *
+ *
* @param point GeoTrackPoint to get values from.
- *
+ *
* @return A list of Waypoint.properies.
*/
@Messages({
"Track_distanceTraveled_displayName=Distance traveled",
"Track_distanceFromHome_displayName=Distance from home point"
})
- private List createPropertyList(GeoTrackPoint point) {
+ private List createPropertyList(GeoTrackPoints.TrackPoint point) {
List list = new ArrayList<>();
Long timestamp = point.getTimeStamp();
diff --git a/Core/src/org/sleuthkit/autopsy/modules/drones/DATExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/drones/DATExtractor.java
index 97cfbd40be..3966317d15 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/drones/DATExtractor.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/drones/DATExtractor.java
@@ -41,11 +41,11 @@ import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
-import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList.GeoTrackPoint;
import org.sleuthkit.datamodel.blackboardutils.GeoArtifactsHelper;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.Blackboard.BlackboardException;
-import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList;
+import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints;
+import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints.TrackPoint;
/**
* Extract drone position data from DJI Phantom drones.
@@ -111,7 +111,7 @@ final class DATExtractor extends DroneExtractor {
}
// Process the csv file
- GeoTrackPointList trackPoints = processCSVFile(context, DATFile, csvFilePath);
+ GeoTrackPoints trackPoints = processCSVFile(context, DATFile, csvFilePath);
if (trackPoints != null && !trackPoints.isEmpty()) {
(new GeoArtifactsHelper(getSleuthkitCase(), getName(), "DatCon", DATFile)).addTrack(DATFile.getName(), trackPoints, null);
@@ -188,8 +188,8 @@ final class DATExtractor extends DroneExtractor {
*
* @throws DroneIngestException
*/
- private GeoTrackPointList processCSVFile(IngestJobContext context, AbstractFile DATFile, String csvFilePath) throws DroneIngestException {
- GeoTrackPointList trackPoints = new GeoTrackPointList();
+ private GeoTrackPoints processCSVFile(IngestJobContext context, AbstractFile DATFile, String csvFilePath) throws DroneIngestException {
+ GeoTrackPoints trackPoints = new GeoTrackPoints();
try (BufferedReader reader = new BufferedReader(new FileReader(new File(csvFilePath)))) {
// First read in the header line and process
String line = reader.readLine();
@@ -201,7 +201,7 @@ final class DATExtractor extends DroneExtractor {
}
String[] values = line.split(","); //NON-NLS
- GeoTrackPoint point = createTrackPoint(headerMap, values);
+ TrackPoint point = createTrackPoint(headerMap, values);
if (point != null) {
trackPoints.addPoint(point);
}
@@ -246,7 +246,7 @@ final class DATExtractor extends DroneExtractor {
*
* @throws DroneIngestException
*/
- private GeoTrackPoint createTrackPoint(Map columnLookup, String[] values) throws DroneIngestException {
+ private TrackPoint createTrackPoint(Map columnLookup, String[] values) throws DroneIngestException {
Double latitude = getDoubleValue(columnLookup.get(HEADER_LAT), values);
Double longitude = getDoubleValue(columnLookup.get(HEADER_LONG), values);
@@ -256,7 +256,7 @@ final class DATExtractor extends DroneExtractor {
return null;
}
- return new GeoTrackPoint(latitude,
+ return new TrackPoint(latitude,
longitude,
getDoubleValue(columnLookup.get(HEADER_ALTITUDE), values),
null,
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java
index 7cb6c72ca2..0f1f97ba97 100644
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java
@@ -52,6 +52,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashS
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb;
+import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SetEvt;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
/**
@@ -94,6 +95,17 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
}
}
});
+
+ HashDbManager.getInstance().addPropertyChangeListener(new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ String propName = evt.getPropertyName();
+ if(propName.equals(SetEvt.DB_ADDED.toString()) ||
+ propName.equals(SetEvt.DB_DELETED.toString())) {
+ hashSetTableModel.refreshModel();
+ }
+ }
+ });
}
@NbBundle.Messages({"HashLookupSettingsPanel.Title=Global Hash Lookup Settings"})
diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardAction.java
index 5b3d661665..236263200a 100644
--- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardAction.java
+++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardAction.java
@@ -59,7 +59,7 @@ import org.sleuthkit.autopsy.report.ReportModule;
@ActionReferences(value = {
@ActionReference(path = "Menu/Tools", position = 301, separatorAfter = 399)
,
- @ActionReference(path = "Toolbars/Case", position = 107)})
+ @ActionReference(path = "Toolbars/Case", position = 106)})
public final class ReportWizardAction extends CallableSystemAction implements Presenter.Toolbar, ActionListener {
private static final Logger logger = Logger.getLogger(ReportWizardAction.class.getName());
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/MultiUserTestTool.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/MultiUserTestTool.java
index 8504bfd7c0..c622d452b5 100755
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/MultiUserTestTool.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/MultiUserTestTool.java
@@ -57,6 +57,7 @@ import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestModuleError;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
+import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.datamodel.AbstractFile;
/**
@@ -83,6 +84,7 @@ class MultiUserTestTool {
"MultiUserTestTool.unableCreatFile=Unable to create a file in case output directory",
"MultiUserTestTool.unableAddFileAsDataSource=Unable to add test file as data source to case",
"MultiUserTestTool.unableToReadTestFileFromDatabase=Unable to read test file info from case database",
+ "MultiUserTestTool.unableToInitializeFilTypeDetector=Unable to initialize File Type Detector",
"MultiUserTestTool.unableToUpdateKWSIndex=Unable to write to Keyword Search index",
"MultiUserTestTool.unableToRunIngest=Unable to run ingest on test data source",
"MultiUserTestTool.unexpectedError=Unexpected error while performing Multi User test",
@@ -187,6 +189,16 @@ class MultiUserTestTool {
}
AbstractFile file = listOfFiles.get(0);
+
+ // Set MIME type of the test file (required to test indexing)
+ FileTypeDetector fileTypeDetector = null;
+ try {
+ fileTypeDetector = new FileTypeDetector();
+ } catch (FileTypeDetector.FileTypeDetectorInitException ex) {
+ return Bundle.MultiUserTestTool_unableToInitializeFilTypeDetector() + ". " + ex.getMessage();
+ }
+ String mimeType = fileTypeDetector.getMIMEType(file);
+ file.setMIMEType(mimeType);
// write to KWS index
KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class);
diff --git a/InternalPythonModules/GPX_Module/GPX_Parser_Module.py b/InternalPythonModules/GPX_Module/GPX_Parser_Module.py
index 6aeb84d5be..fe92d0d659 100644
--- a/InternalPythonModules/GPX_Module/GPX_Parser_Module.py
+++ b/InternalPythonModules/GPX_Module/GPX_Parser_Module.py
@@ -37,12 +37,10 @@ from org.sleuthkit.datamodel import BlackboardArtifact
from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper
-from org.sleuthkit.datamodel.blackboardutils.attributes import TskGeoWaypointsUtil
-from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil import GeoWaypointList
-from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil.GeoWaypointList import GeoWaypoint
-from org.sleuthkit.datamodel.blackboardutils.attributes import TskGeoTrackpointsUtil
-from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil import GeoTrackPointList
-from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList import GeoTrackPoint
+from org.sleuthkit.datamodel.blackboardutils.attributes import GeoWaypoints
+from org.sleuthkit.datamodel.blackboardutils.attributes.GeoWaypoints import Waypoint
+from org.sleuthkit.datamodel.blackboardutils.attributes import GeoTrackPoints
+from org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints import TrackPoint
from org.sleuthkit.autopsy.datamodel import ContentUtils
from org.sleuthkit.autopsy.ingest import IngestModule
from org.sleuthkit.autopsy.ingest.IngestModule import IngestModuleException
@@ -166,7 +164,7 @@ class GPXParserDataSourceIngestModule(DataSourceIngestModule):
if self.writeDebugMsgs: self.log(Level.INFO, "Processing tracks from " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")")
for track in gpx.tracks:
for segment in track.segments:
- geoPointList = TskGeoTrackpointsUtil.GeoTrackPointList()
+ geoPointList = GeoTrackPoints()
for point in segment.points:
elevation = 0
@@ -180,7 +178,7 @@ class GPXParserDataSourceIngestModule(DataSourceIngestModule):
except Exception as e:
self.log(Level.WARNING, "Error getting track timestamp from " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + str(e))
- geoPointList.addPoint(GeoTrackPoint(point.latitude, point.longitude, elevation, None, 0, 0, 0, timeStamp))
+ geoPointList.addPoint(TrackPoint(point.latitude, point.longitude, elevation, None, 0, 0, 0, timeStamp))
try:
geoArtifactHelper.addTrack("Track", geoPointList, None)
@@ -213,10 +211,10 @@ class GPXParserDataSourceIngestModule(DataSourceIngestModule):
if self.writeDebugMsgs: self.log(Level.INFO, "Processing routes from " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")")
for route in gpx.routes:
- geoWaypointList = TskGeoWaypointsUtil.GeoWaypointList()
+ geoWaypoints = GeoWaypoints()
for point in route.points:
- geoWaypointList.addPoint(GeoWaypoint(point.latitude, point.longitude, point.elevation, point.name))
+ geoWaypointList.addPoint(Waypoint(point.latitude, point.longitude, point.elevation, point.name))
try:
geoArtifactHelper.addRoute(None, None, geoWaypointList, None)
diff --git a/InternalPythonModules/android/calllog.py b/InternalPythonModules/android/calllog.py
index 5b3faf0697..13775e80f7 100644
--- a/InternalPythonModules/android/calllog.py
+++ b/InternalPythonModules/android/calllog.py
@@ -103,10 +103,7 @@ class CallLogAnalyzer(general.AndroidComponentAnalyzer):
calleeId = None
timeStamp = resultSet.getLong("date") / 1000
-
number = resultSet.getString("number")
- if not general.isValidPhoneNumer(number):
- number = None
duration = resultSet.getLong("duration") # duration of call is in seconds
name = resultSet.getString("name") # name of person dialed or called. None if unregistered
diff --git a/InternalPythonModules/android/general.py b/InternalPythonModules/android/general.py
index daa789a57c..4048c05c0f 100644
--- a/InternalPythonModules/android/general.py
+++ b/InternalPythonModules/android/general.py
@@ -45,19 +45,15 @@ def appendAttachmentList(msgBody, attachmentsList):
"""
Checks if the given string might be a phone number.
"""
-def isValidPhoneNumer(data):
- try:
- return CommunicationsUtils.normalizePhoneNum(data) is not None
- except TskCoreException as ex:
- return False
+def isValidPhoneNumber(data):
+ return CommunicationsUtils.isValidPhoneNumber(data)
+
"""
Checks if the given string is a valid email address.
"""
def isValidEmailAddress(data):
- try:
- return CommunicationsUtils.normalizeEmailAddress(data) is not None
- except TskCoreException as ex:
- return False
+ return CommunicationsUtils.isValidEmailAddress(data)
+
diff --git a/InternalPythonModules/android/googlemaplocation.py b/InternalPythonModules/android/googlemaplocation.py
index 8e393dcee2..2c33146b21 100644
--- a/InternalPythonModules/android/googlemaplocation.py
+++ b/InternalPythonModules/android/googlemaplocation.py
@@ -43,8 +43,8 @@ from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel.Blackboard import BlackboardException
from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper
-from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil import GeoWaypointList
-from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil.GeoWaypointList import GeoWaypoint
+from org.sleuthkit.datamodel.blackboardutils.attributes import GeoWaypoints
+from org.sleuthkit.datamodel.blackboardutils.attributes.GeoWaypoints import Waypoint
import traceback
import general
@@ -117,9 +117,9 @@ class GoogleMapLocationAnalyzer(general.AndroidComponentAnalyzer):
source_lat = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lat"))
source_lng = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lng"))
- waypointlist = GeoWaypointList()
- waypointlist.addPoint(GeoWaypoint(source_lat, source_lng, None, None))
- waypointlist.addPoint(GeoWaypoint(dest_lat, dest_lng, None, dest_address))
+ waypointlist = GeoWaypoints()
+ waypointlist.addPoint(Waypoint(source_lat, source_lng, None, None))
+ waypointlist.addPoint(Waypoint(dest_lat, dest_lng, None, dest_address))
artifactHelper.addRoute(dest_title, time, waypointlist, None)
diff --git a/InternalPythonModules/android/oruxmaps.py b/InternalPythonModules/android/oruxmaps.py
index 7a939e1972..283eab38b2 100644
--- a/InternalPythonModules/android/oruxmaps.py
+++ b/InternalPythonModules/android/oruxmaps.py
@@ -45,7 +45,8 @@ from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel.Blackboard import BlackboardException
from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper
-from org.sleuthkit.datamodel.blackboardutils.attributes import TskGeoTrackpointsUtil
+from org.sleuthkit.datamodel.blackboardutils.attributes import GeoTrackPoints
+from org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints import TrackPoint
import traceback
import general
@@ -139,14 +140,14 @@ class OruxMapsAnalyzer(general.AndroidComponentAnalyzer):
trackpointsQueryString = "SELECT trkptlat, trkptlon, trkptalt, trkpttime FROM trackpoints WHERE trkptseg = " + segmentId
trackpointsResultSet = oruxMapsTrackpointsDb.runQuery(trackpointsQueryString)
if trackpointsResultSet is not None:
- geoPointList = TskGeoTrackpointsUtil.GeoTrackPointList()
+ geoPointList = GeoTrackPoints()
while trackpointsResultSet.next():
latitude = trackpointsResultSet.getDouble("trkptlat")
longitude = trackpointsResultSet.getDouble("trkptlon")
altitude = trackpointsResultSet.getDouble("trkptalt")
time = trackpointsResultSet.getLong("trkpttime") / 1000 # milliseconds since unix epoch
- geoPointList.addPoint(TskGeoTrackpointsUtil.GeoTrackPointList.GeoTrackPoint(latitude, longitude, altitude, segmentName, 0, 0, 0, time))
+ geoPointList.addPoint(TrackPoint(latitude, longitude, altitude, segmentName, 0, 0, 0, time))
try:
geoartifact = geoArtifactHelper.addTrack(segmentName, geoPointList, None)
diff --git a/InternalPythonModules/android/textnow.py b/InternalPythonModules/android/textnow.py
index e05763cae9..005e1191dd 100644
--- a/InternalPythonModules/android/textnow.py
+++ b/InternalPythonModules/android/textnow.py
@@ -286,7 +286,7 @@ class TextNowContactsParser(TskContactsParser):
def get_phone(self):
number = self.result_set.getString("number")
- return (number if general.isValidPhoneNumer(number) else None)
+ return (number if general.isValidPhoneNumber(number) else None)
def get_email(self):
# occasionally the 'number' column may have an email address instead
diff --git a/InternalPythonModules/android/whatsapp.py b/InternalPythonModules/android/whatsapp.py
index 5346545450..c67502d22b 100644
--- a/InternalPythonModules/android/whatsapp.py
+++ b/InternalPythonModules/android/whatsapp.py
@@ -435,7 +435,7 @@ class WhatsAppContactsParser(TskContactsParser):
def get_phone(self):
number = self.result_set.getString("number")
- return (number if general.isValidPhoneNumer(number) else None)
+ return (number if general.isValidPhoneNumber(number) else None)
def get_email(self):
# occasionally the 'number' column may have an email address instead
diff --git a/TSKVersion.xml b/TSKVersion.xml
index 561c00581d..38e614169a 100644
--- a/TSKVersion.xml
+++ b/TSKVersion.xml
@@ -1,3 +1,3 @@
-
+
diff --git a/docs/doxygen/modReport.dox b/docs/doxygen/modReport.dox
index 5799314acf..563a151c43 100644
--- a/docs/doxygen/modReport.dox
+++ b/docs/doxygen/modReport.dox
@@ -3,63 +3,18 @@
\section report_summary Overview
Report modules allow Autopsy users to create different report types. Autopsy comes with modules to generate HTML and Excel artifact reports, a tab delimited File report, a Keyhole Markup Language (KML) report for Google Earth data, and a body file for timeline creation. You can make additional modules to create custom output formats.
-There are three types of reporting modules that differ in how the data is organized.
-- Table report modules organize the data into tables. If your output is in table format, this type of module will be easier to make because Autopsy does a lot of the organizing work for you.
-- File report modules are also table-based, but they specifically deal with reporting on the Files in the case, not artifacts.
-- General report modules are free form and you are allowed to organize the output however you want.
-
-Table report modules require their subclasses to override methods to start and end tables, and add rows to those tables. These methods are provided data, generated from a default configuration panel, for the module to report on. Because of this, when creating a table report module one only needs to focus on how to display the data, not how to find it.
-
-File report modules are similar to table report modules, but only require their sub-classes to start and end a single table, and add rows to that table. The methods are given an AbstractFile and a list of FileReportDataTypes, which specify what information about the file should be added to the report. The data can be extracted from the file by calling the FileReportDataTypes getValue method with the file as it's argument.
-
-On the other hand, general report modules have a single method to generate the report. This method gives the module freedom to find and process any data it so chooses. General modules also have the ability to provide a configuration panel, allowing the user to choose from various displayed settings. The report module may then use the user's selection to generate a more specific report.
+All custom report modules will be general report modules. General report modules have a single method to generate the report. This method gives the module freedom to find and process any data it so chooses. General modules also have the ability to provide a configuration panel, allowing the user to choose from various displayed settings. The report module may then use the user's selection to generate a more specific report.
General modules are also given the responsibility of updating their report's progress bar and processing label in the UI. A progress panel is given to every general report module. It contains basic API to start, stop, and add to the progress bar, as well as update the processing label. The module is also expected to check the progress bar's status occasionally to see if the user has manually canceled the report.
\section report_create_module Creating a Report Module
-To create a report module, start off by creating a new Java or Python (Jython) class and implementing (Java) or inheriting (Jython) the appropriate interface:
-- org.sleuthkit.autopsy.report.TableReportModule
-- org.sleuthkit.autopsy.report.FileReportModule
-- org.sleuthkit.autopsy.report.GeneralReportModule
-
-All three of these interfaces extend the org.sleuthkit.autopsy.report.ReportModule interface that defines the following methods:
+To create a report module, start off by creating a new Java or Python (Jython) class and implementing (Java) or inheriting (Jython) from org.sleuthkit.autopsy.report.GeneralReportModule. You'll need to override multiple methods including the following:
- org.sleuthkit.autopsy.report.ReportModule.getName()
- org.sleuthkit.autopsy.report.ReportModule.getDescription()
- org.sleuthkit.autopsy.report.ReportModule.getRelativeFilePath()
-
-These methods will be called by Autopsy when it is presenting the reporting UI to a user.
-
-\subsection report_create_module_table Creating A Table Report Module
-If you implement TableReportModule, you should override the methods:
-- org.sleuthkit.autopsy.report.TableReportModule.startReport(String path)
-- org.sleuthkit.autopsy.report.TableReportModule.endReport()
-- org.sleuthkit.autopsy.report.TableReportModule.startDataType(String title)
-- org.sleuthkit.autopsy.report.TableReportModule.endDataType()
-- org.sleuthkit.autopsy.report.TableReportModule.startSet(String setName)
-- org.sleuthkit.autopsy.report.TableReportModule.endSet()
-- org.sleuthkit.autopsy.report.TableReportModule.addSetIndex(List sets)
-- org.sleuthkit.autopsy.report.TableReportModule.addSetElement(String elementName)
-- org.sleuthkit.autopsy.report.TableReportModule.startTable(List titles)
-- org.sleuthkit.autopsy.report.TableReportModule.endTable()
-- org.sleuthkit.autopsy.report.TableReportModule.addRow(List row)
-- org.sleuthkit.autopsy.report.TableReportModule.dateToString(long date)
-
-When generating table module reports, Autopsy will iterate through a list of user selected data, and call methods such as addRow(List row) for every "row" of data it finds, or startTable(List titles) for every new category it finds. Developers are guaranteed that every start of a data type, set, or table will be followed by an appropriate end. The focus for a table report module should be to take the given information and display it in a user friendly format. See org.sleuthkit.autopsy.report.ReportExcel for an example.
-
-\subsection report_create_module_file Creating a File Report Module
-If you implement FileReportModule, the overriden methods will be:
-- org.sleuthkit.autopsy.report.FileReportModule.startReport(String path)
-- org.sleuthkit.autopsy.report.FileReportModule.endReport()
-- org.sleuthkit.autopsy.report.FileReportModule.startTable(List headers)
-- org.sleuthkit.autopsy.report.FileReportModule.endTable()
-- org.sleuthkit.autopsy.report.FileReportModule.addRow(AbstractFile toAdd, List columns)
-
-As when generating table module reports, Autopsy will iterate through a list of user selected data (which are represented by FileReportDataTypes), and call addRow(AbstractFile toAdd, List columns) for every abstract file in the case. Developers are guaranteed that the order of method calls will be startReport(), startTable(List headers), addRow(AbstractFile toAdd, List columns), AbstractFile toAdd, List columns),..., endTable(), endReport().
-
-\subsection report_create_module_general Creating a General Report Module
-
-If you implement GeneralReportModule, the overridden methods will be:
- org.sleuthkit.autopsy.report.GeneralReportModule.generateReport(String reportPath, ReportProgressPanel progressPanel)
+
+If your report module requires configuration, you'll need to override:
- org.sleuthkit.autopsy.report.GeneralReportModule.getConfigurationPanel()
For general report modules, Autopsy will simply call the generateReport(String reportPath, ReportProgressPanel progressPanel) method and leave it up to the module to aquire and report data in its desired format. The only requirements are that the module saves to the given report path and updates the org.sleuthkit.autopsy.report.ReportProgressPanel as the report progresses.
@@ -90,22 +45,14 @@ if (null == searchService) {
\subsection report_create_module_layer Installing your Report Module
-Report modules developed using Java must be registered in a layer.xml file. This file allows Autopsy to find the report module.
+Adding a service provider annotation allows Autopsy to find your report module.
-An example entry in a layer.xml is shown below:
\code
-
-
-
-
-
-
-
+@ServiceProvider(service = GeneralReportModule.class)
+public class SampleReportModule implements GeneralReportModule {
\endcode
-In the above example, "org-sleuthkit-autopsy-report-ReportHTML" should be replaced with the package path to your report module.
-
-It is also important to remember to include a getDefault() method in your report module. As shown in the code above, the instance to each report module is accessed via it's getDefault() method.
+It is also important to remember to include a getDefault() method in your report module. As shown in the code above, the instance to each report module is accessed via its getDefault() method.
For example:
\code
diff --git a/unix_setup.sh b/unix_setup.sh
index badf2a1505..dc92f38236 100644
--- a/unix_setup.sh
+++ b/unix_setup.sh
@@ -5,7 +5,7 @@
# NOTE: update_sleuthkit_version.pl updates this value and relies
# on it keeping the same name and whitespace. Don't change it.
-TSK_VERSION=4.8.0
+TSK_VERSION=4.9.0
# In the beginning...