Autopsy  4.5.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ReportKML.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2014-2018 Basis Technology Corp.
6  * contact: carrier <at> sleuthkit <dot> org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 package org.sleuthkit.autopsy.report;
21 
22 import javax.swing.JPanel;
23 
24 import org.openide.util.NbBundle;
27 import org.sleuthkit.datamodel.*;
29 import org.sleuthkit.datamodel.BlackboardArtifact;
30 import java.io.File;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.OutputStream;
35 import java.nio.file.Path;
36 import java.nio.file.Paths;
37 import java.text.SimpleDateFormat;
38 import java.util.logging.Level;
39 import org.jdom2.Document;
40 import org.jdom2.Element;
41 import org.jdom2.Namespace;
42 import org.jdom2.output.Format;
43 import org.jdom2.output.XMLOutputter;
44 import org.jdom2.CDATA;
45 import org.openide.filesystems.FileUtil;
46 
50 class ReportKML implements GeneralReportModule {
51 
52  private static final Logger logger = Logger.getLogger(ReportKML.class.getName());
53  private static final String KML_STYLE_FILE = "style.kml";
54  private static final String REPORT_KML = "ReportKML.kml";
55  private static final String STYLESHEETS_PATH = "/org/sleuthkit/autopsy/report/stylesheets/";
56  private static ReportKML instance = null;
57  private Case currentCase;
58  private SleuthkitCase skCase;
59  private final SimpleDateFormat kmlDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
60  private Namespace ns;
61  private final String SEP = "<br>";
62 
63  private enum FeatureColor {
64  RED("style.kml#redFeature"),
65  GREEN("style.kml#greenFeature"),
66  BLUE("style.kml#blueFeature"),
67  PURPLE("style.kml#purpleFeature"),
68  WHITE("style.kml#whiteFeature"),
69  YELLOW("style.kml#yellowFeature");
70  private String color;
71 
72  FeatureColor(String color) {
73  this.color = color;
74  }
75 
76  String getColor() {
77  return this.color;
78  }
79  }
80 
81  // Hidden constructor for the report
82  private ReportKML() {
83  }
84 
85  // Get the default implementation of this report
86  public static synchronized ReportKML getDefault() {
87  if (instance == null) {
88  instance = new ReportKML();
89  }
90  return instance;
91  }
92 
99  @Override
100  public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) {
101 
102  // Start the progress bar and setup the report
103  progressPanel.setIndeterminate(true);
104  progressPanel.start();
105  progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.querying"));
106  String kmlFileFullPath = baseReportDir + REPORT_KML; //NON-NLS
107 
108  currentCase = Case.getCurrentCase();
109  skCase = currentCase.getSleuthkitCase();
110 
111  progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.loading"));
112 
113  ns = Namespace.getNamespace("", "http://www.opengis.net/kml/2.2"); //NON-NLS
114 
115  Element kml = new Element("kml", ns); //NON-NLS
116  kml.addNamespaceDeclaration(Namespace.getNamespace("gx", "http://www.google.com/kml/ext/2.2")); //NON-NLS
117  kml.addNamespaceDeclaration(Namespace.getNamespace("kml", "http://www.opengis.net/kml/2.2")); //NON-NLS
118  kml.addNamespaceDeclaration(Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom")); //NON-NLS
119  Document kmlDocument = new Document(kml);
120 
121  Element document = new Element("Document", ns); //NON-NLS
122  kml.addContent(document);
123 
124  Element name = new Element("name", ns); //NON-NLS
125  ReportBranding rb = new ReportBranding();
126  name.setText(rb.getReportTitle() + " KML"); //NON-NLS
127  document.addContent(name);
128 
129  // Check if ingest has finished
130  if (IngestManager.getInstance().isIngestRunning()) {
131  Element ingestwarning = new Element("snippet", ns); //NON-NLS
132  ingestwarning.addContent(NbBundle.getMessage(this.getClass(), "ReportBodyFile.ingestWarning.text")); //NON-NLS
133  document.addContent(ingestwarning);
134  }
135 
136  // Create folder structure
137  Element gpsExifMetadataFolder = new Element("Folder", ns); //NON-NLS
138  CDATA cdataExifMetadataFolder = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/camera-icon-16.png"); //NON-NLS
139  Element hrefExifMetadata = new Element("href", ns).addContent(cdataExifMetadataFolder); //NON-NLS
140  gpsExifMetadataFolder.addContent(new Element("Icon", ns).addContent(hrefExifMetadata)); //NON-NLS
141 
142  Element gpsBookmarksFolder = new Element("Folder", ns); //NON-NLS
143  CDATA cdataBookmarks = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gpsfav.png"); //NON-NLS
144  Element hrefBookmarks = new Element("href", ns).addContent(cdataBookmarks); //NON-NLS
145  gpsBookmarksFolder.addContent(new Element("Icon", ns).addContent(hrefBookmarks)); //NON-NLS
146 
147  Element gpsLastKnownLocationFolder = new Element("Folder", ns); //NON-NLS
148  CDATA cdataLastKnownLocation = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-lastlocation.png"); //NON-NLS
149  Element hrefLastKnownLocation = new Element("href", ns).addContent(cdataLastKnownLocation); //NON-NLS
150  gpsLastKnownLocationFolder.addContent(new Element("Icon", ns).addContent(hrefLastKnownLocation)); //NON-NLS
151 
152  Element gpsRouteFolder = new Element("Folder", ns); //NON-NLS
153  CDATA cdataRoute = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png"); //NON-NLS
154  Element hrefRoute = new Element("href", ns).addContent(cdataRoute); //NON-NLS
155  gpsRouteFolder.addContent(new Element("Icon", ns).addContent(hrefRoute)); //NON-NLS
156 
157  Element gpsSearchesFolder = new Element("Folder", ns); //NON-NLS
158  CDATA cdataSearches = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-search.png"); //NON-NLS
159  Element hrefSearches = new Element("href", ns).addContent(cdataSearches); //NON-NLS
160  gpsSearchesFolder.addContent(new Element("Icon", ns).addContent(hrefSearches)); //NON-NLS
161 
162  Element gpsTrackpointsFolder = new Element("Folder", ns); //NON-NLS
163  CDATA cdataTrackpoints = new CDATA("https://raw.githubusercontent.com/sleuthkit/autopsy/develop/Core/src/org/sleuthkit/autopsy/images/gps-trackpoint.png"); //NON-NLS
164  Element hrefTrackpoints = new Element("href", ns).addContent(cdataTrackpoints); //NON-NLS
165  gpsTrackpointsFolder.addContent(new Element("Icon", ns).addContent(hrefTrackpoints)); //NON-NLS
166 
167  gpsExifMetadataFolder.addContent(new Element("name", ns).addContent("EXIF Metadata")); //NON-NLS
168  gpsBookmarksFolder.addContent(new Element("name", ns).addContent("GPS Bookmarks")); //NON-NLS
169  gpsLastKnownLocationFolder.addContent(new Element("name", ns).addContent("GPS Last Known Location")); //NON-NLS
170  gpsRouteFolder.addContent(new Element("name", ns).addContent("GPS Routes")); //NON-NLS
171  gpsSearchesFolder.addContent(new Element("name", ns).addContent("GPS Searches")); //NON-NLS
172  gpsTrackpointsFolder.addContent(new Element("name", ns).addContent("GPS Trackpoints")); //NON-NLS
173 
174  document.addContent(gpsExifMetadataFolder);
175  document.addContent(gpsBookmarksFolder);
176  document.addContent(gpsLastKnownLocationFolder);
177  document.addContent(gpsRouteFolder);
178  document.addContent(gpsSearchesFolder);
179  document.addContent(gpsTrackpointsFolder);
180 
181  ReportProgressPanel.ReportStatus result = ReportProgressPanel.ReportStatus.COMPLETE;
182 
198  try {
199  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) {
200  try {
201  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
202  String desc = getDescriptionFromArtifact(artifact, "EXIF Metadata With Locations"); //NON-NLS
203  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
204  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
205  Element point = makePoint(lat, lon, getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE));
206 
207  if (lat != null && lat != 0.0 && lon != null && lon != 0.0) {
208  AbstractFile abstractFile = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
209  Path path = null;
210  copyFileUsingStream(abstractFile, Paths.get(baseReportDir, abstractFile.getName()).toFile());
211  try {
212  path = Paths.get(removeLeadingImgAndVol(abstractFile.getUniquePath()));
213  } catch (TskCoreException ex) {
214  path = Paths.get(abstractFile.getParentPath(), abstractFile.getName());
215  }
216  String formattedCoordinates = String.format("%.2f, %.2f", lat, lon);
217  if (path == null) {
218  path = Paths.get(abstractFile.getName());
219  }
220  gpsExifMetadataFolder.addContent(makePlacemarkWithPicture(abstractFile.getName(), FeatureColor.RED, desc, timestamp, point, path, formattedCoordinates));
221  }
222  } catch (Exception ex) {
223  logger.log(Level.SEVERE, "Could not extract photo information.", ex); //NON-NLS
224  result = ReportProgressPanel.ReportStatus.ERROR;
225  }
226  }
227  } catch (TskCoreException ex) {
228  logger.log(Level.SEVERE, "Could not extract photos with EXIF metadata.", ex); //NON-NLS
229  result = ReportProgressPanel.ReportStatus.ERROR;
230  }
231 
232  try {
233  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)) {
234  try {
235  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
236  String desc = getDescriptionFromArtifact(artifact, "GPS Bookmark"); //NON-NLS
237  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
238  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
239  Element point = makePoint(lat, lon, getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE));
240  String bookmarkName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
241  String formattedCoordinates = String.format("%.2f, %.2f", lat, lon);
242  gpsBookmarksFolder.addContent(makePlacemark(bookmarkName, FeatureColor.BLUE, desc, timestamp, point, formattedCoordinates));
243  } catch (Exception ex) {
244  logger.log(Level.SEVERE, "Could not extract Bookmark information.", ex); //NON-NLS
245  result = ReportProgressPanel.ReportStatus.ERROR;
246  }
247  }
248  } catch (TskCoreException ex) {
249  logger.log(Level.SEVERE, "Could not get GPS Bookmarks from database.", ex); //NON-NLS
250  result = ReportProgressPanel.ReportStatus.ERROR;
251  }
252 
253  try {
254  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION)) {
255  try {
256  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
257  String desc = getDescriptionFromArtifact(artifact, "GPS Last Known Location"); //NON-NLS
258  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
259  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
260  Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
261  Element point = makePoint(lat, lon, alt);
262  String formattedCoordinates = String.format("%.2f, %.2f", lat, lon);
263  gpsLastKnownLocationFolder.addContent(makePlacemark("Last Known Location", FeatureColor.PURPLE, desc, timestamp, point, formattedCoordinates)); //NON-NLS
264  } catch (Exception ex) {
265  logger.log(Level.SEVERE, "Could not extract Last Known Location information.", ex); //NON-NLS
266  result = ReportProgressPanel.ReportStatus.ERROR;
267  }
268  }
269  } catch (TskCoreException ex) {
270  logger.log(Level.SEVERE, "Could not get GPS Last Known Location from database.", ex); //NON-NLS
271  result = ReportProgressPanel.ReportStatus.ERROR;
272  }
273 
274  try {
275  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE)) {
276  try {
277  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
278  String desc = getDescriptionFromArtifact(artifact, "GPS Route");
279  Double latitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
280  Double longitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
281  Double latitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
282  Double longitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END);
283  Double altitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
284 
285  Element route = makeLineString(latitudeStart, longitudeStart, altitude, latitudeEnd, longitudeEnd, altitude);
286  Element startingPoint = makePoint(latitudeStart, longitudeStart, altitude);
287  Element endingPoint = makePoint(latitudeEnd, longitudeEnd, altitude);
288 
289  String formattedCoordinates = String.format("%.2f, %.2f to %.2f, %.2f", latitudeStart, longitudeStart, latitudeEnd, longitudeEnd);
290  gpsRouteFolder.addContent(makePlacemark("As-the-crow-flies Route", FeatureColor.GREEN, desc, timestamp, route, formattedCoordinates)); //NON-NLS
291 
292  formattedCoordinates = String.format("%.2f, %.2f", latitudeStart, longitudeStart);
293  gpsRouteFolder.addContent(makePlacemark("Start", FeatureColor.GREEN, desc, timestamp, startingPoint, formattedCoordinates)); //NON-NLS
294 
295  formattedCoordinates = String.format("%.2f, %.2f", latitudeEnd, longitudeEnd);
296  gpsRouteFolder.addContent(makePlacemark("End", FeatureColor.GREEN, desc, timestamp, endingPoint, formattedCoordinates)); //NON-NLS
297  } catch (Exception ex) {
298  logger.log(Level.SEVERE, "Could not extract GPS Route information.", ex); //NON-NLS
299  result = ReportProgressPanel.ReportStatus.ERROR;
300  }
301  }
302  } catch (TskCoreException ex) {
303  logger.log(Level.SEVERE, "Could not get GPS Routes from database.", ex); //NON-NLS
304  result = ReportProgressPanel.ReportStatus.ERROR;
305  }
306 
307  try {
308  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH)) {
309  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
310  String desc = getDescriptionFromArtifact(artifact, "GPS Search"); //NON-NLS
311  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
312  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
313  Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
314  Element point = makePoint(lat, lon, alt);
315  String formattedCoordinates = String.format("%.2f, %.2f", lat, lon);
316  String searchName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
317  if (searchName == null || searchName.isEmpty()) {
318  searchName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION);
319  }
320  if (searchName == null || searchName.isEmpty()) {
321  searchName = "GPS Search";
322  }
323  gpsSearchesFolder.addContent(makePlacemark(searchName, FeatureColor.WHITE, desc, timestamp, point, formattedCoordinates)); //NON-NLS
324  }
325  } catch (TskCoreException ex) {
326  logger.log(Level.SEVERE, "Could not get GPS Searches from database.", ex); //NON-NLS
327  result = ReportProgressPanel.ReportStatus.ERROR;
328  }
329 
330  try {
331  for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)) {
332  try {
333  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
334  String desc = getDescriptionFromArtifact(artifact, "GPS Trackpoint"); //NON-NLS
335  Double lat = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
336  Double lon = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
337  Double alt = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
338  Element point = makePoint(lat, lon, alt);
339  String formattedCoordinates = String.format("%.2f, %.2f, %.2f", lat, lon, alt);
340  String trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
341  if (trackName == null || trackName.isEmpty()) {
342  trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME);
343  }
344  if (trackName == null || trackName.isEmpty()) {
345  trackName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG);
346  }
347  if (trackName == null || trackName.isEmpty()) {
348  trackName = "GPS Trackpoint";
349  }
350  gpsTrackpointsFolder.addContent(makePlacemark(trackName, FeatureColor.YELLOW, desc, timestamp, point, formattedCoordinates));
351  } catch (Exception ex) {
352  logger.log(Level.SEVERE, "Could not extract Trackpoint information.", ex); //NON-NLS
353  result = ReportProgressPanel.ReportStatus.ERROR;
354  }
355  }
356  } catch (TskCoreException ex) {
357  logger.log(Level.SEVERE, "Could not get GPS Trackpoints from database.", ex); //NON-NLS
358  result = ReportProgressPanel.ReportStatus.ERROR;
359  }
360 
361  // Copy the style sheet
362  try {
363  InputStream input = getClass().getResourceAsStream(STYLESHEETS_PATH + KML_STYLE_FILE); // Preserve slash direction
364  OutputStream output = new FileOutputStream(baseReportDir + KML_STYLE_FILE); // Preserve slash direction
365  FileUtil.copy(input, output);
366  } catch (IOException ex) {
367  logger.log(Level.SEVERE, "Error placing KML stylesheet. The .KML file will not function properly.", ex); //NON-NLS
368  result = ReportProgressPanel.ReportStatus.ERROR;
369  }
370 
371  try (FileOutputStream writer = new FileOutputStream(kmlFileFullPath)) {
372  XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
373  outputter.output(kmlDocument, writer);
374  String prependedStatus = "";
375  if (result == ReportProgressPanel.ReportStatus.ERROR) {
376  prependedStatus = "Incomplete ";
377  }
378  Case.getCurrentCase().addReport(kmlFileFullPath,
379  NbBundle.getMessage(this.getClass(), "ReportKML.genReport.srcModuleName.text"),
380  prependedStatus + NbBundle.getMessage(this.getClass(), "ReportKML.genReport.reportName"));
381  } catch (IOException ex) {
382  logger.log(Level.SEVERE, "Could not write the KML file.", ex); //NON-NLS
383  progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
384  } catch (TskCoreException ex) {
385  String errorMessage = String.format("Error adding %s to case as a report", kmlFileFullPath); //NON-NLS
386  logger.log(Level.SEVERE, errorMessage, ex);
387  result = ReportProgressPanel.ReportStatus.ERROR;
388  }
389 
390  progressPanel.complete(result);
391  }
392 
401  private Double getDouble(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
402  Double returnValue = null;
403  try {
404  BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
405  if (bba != null) {
406  Double value = bba.getValueDouble();
407  if (value != null) {
408  returnValue = value;
409  }
410  }
411  } catch (TskCoreException ex) {
412  logger.log(Level.SEVERE, "Error getting Double value: " + type.toString(), ex); //NON-NLS
413  }
414  return returnValue;
415  }
416 
425  private Long getLong(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
426  Long returnValue = null;
427  try {
428  BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
429  if (bba != null) {
430  Long value = bba.getValueLong();
431  if (value != null) {
432  returnValue = value;
433  }
434  }
435  } catch (TskCoreException ex) {
436  logger.log(Level.SEVERE, "Error getting Long value: " + type.toString(), ex); //NON-NLS
437  }
438  return returnValue;
439  }
440 
449  private Integer getInteger(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
450  Integer returnValue = null;
451  try {
452  BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
453  if (bba != null) {
454  Integer value = bba.getValueInt();
455  if (value != null) {
456  returnValue = value;
457  }
458  }
459  } catch (TskCoreException ex) {
460  logger.log(Level.SEVERE, "Error getting Integer value: " + type.toString(), ex); //NON-NLS
461  }
462  return returnValue;
463  }
464 
473  private String getString(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) {
474  String returnValue = null;
475  try {
476  BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
477  if (bba != null) {
478  String value = bba.getValueString();
479  if (value != null && !value.isEmpty()) {
480  returnValue = value;
481  }
482  }
483  } catch (TskCoreException ex) {
484  logger.log(Level.SEVERE, "Error getting String value: " + type.toString(), ex); //NON-NLS
485  }
486  return returnValue;
487  }
488 
506  private String getDescriptionFromArtifact(BlackboardArtifact artifact, String featureType) {
507  StringBuilder result = new StringBuilder("<h3>" + featureType + "</h3>"); //NON-NLS
508 
509  String name = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
510  if (name != null && !name.isEmpty()) {
511  result.append("<b>Name:</b> ").append(name).append(SEP); //NON-NLS
512  }
513 
514  String location = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION);
515  if (location != null && !location.isEmpty()) {
516  result.append("<b>Location:</b> ").append(location).append(SEP); //NON-NLS
517  }
518 
519  Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
520  if (timestamp != null) {
521  result.append("<b>Timestamp:</b> ").append(getTimeStamp(timestamp)).append(SEP); //NON-NLS
522  result.append("<b>Unix timestamp:</b> ").append(timestamp).append(SEP); //NON-NLS
523  }
524 
525  Long startingTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START);
526  if (startingTimestamp != null) {
527  result.append("<b>Starting Timestamp:</b> ").append(getTimeStamp(startingTimestamp)).append(SEP); //NON-NLS
528  result.append("<b>Starting Unix timestamp:</b> ").append(startingTimestamp).append(SEP); //NON-NLS
529  }
530 
531  Long endingTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END);
532  if (endingTimestamp != null) {
533  result.append("<b>Ending Timestamp:</b> ").append(getTimeStamp(endingTimestamp)).append(SEP); //NON-NLS
534  result.append("<b>Ending Unix timestamp:</b> ").append(endingTimestamp).append(SEP); //NON-NLS
535  }
536 
537  Long createdTimestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
538  if (createdTimestamp != null) {
539  result.append("<b>Created Timestamp:</b> ").append(getTimeStamp(createdTimestamp)).append(SEP); //NON-NLS
540  result.append("<b>Created Unix timestamp:</b> ").append(createdTimestamp).append(SEP); //NON-NLS
541  }
542 
543  Double latitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE);
544  if (latitude != null) {
545  result.append("<b>Latitude:</b> ").append(latitude).append(SEP); //NON-NLS
546  }
547 
548  Double longitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE);
549  if (longitude != null) {
550  result.append("<b>Longitude:</b> ").append(longitude).append(SEP); //NON-NLS
551  }
552 
553  Double latitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START);
554  if (latitudeStart != null) {
555  result.append("<b>Latitude Start:</b> ").append(latitudeStart).append(SEP); //NON-NLS
556  }
557 
558  Double longitudeStart = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START);
559  if (longitudeStart != null) {
560  result.append("<b>Longitude Start:</b> ").append(longitudeStart).append(SEP); //NON-NLS
561  }
562 
563  Double latitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END);
564  if (latitudeEnd != null) {
565  result.append("<b>Latitude End:</b> ").append(latitudeEnd).append(SEP); //NON-NLS
566  }
567 
568  Double longitudeEnd = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END);
569  if (longitudeEnd != null) {
570  result.append("<b>Longitude End:</b> ").append(longitudeEnd).append(SEP); //NON-NLS
571  }
572 
573  Double velocity = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_VELOCITY);
574  if (velocity != null) {
575  result.append("<b>Velocity:</b> ").append(velocity).append(SEP); //NON-NLS
576  }
577 
578  Double altitude = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE);
579  if (altitude != null) {
580  result.append("<b>Altitude:</b> ").append(altitude).append(SEP); //NON-NLS
581  }
582 
583  Double bearing = getDouble(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_BEARING);
584  if (bearing != null) {
585  result.append("<b>Bearing:</b> ").append(bearing).append(SEP); //NON-NLS
586  }
587 
588  Integer hPrecision = getInteger(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_HPRECISION);
589  if (hPrecision != null) {
590  result.append("<b>Horizontal Precision Figure of Merit:</b> ").append(hPrecision).append(SEP); //NON-NLS
591  }
592 
593  Integer vPrecision = getInteger(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_VPRECISION);
594  if (vPrecision != null) {
595  result.append("<b>Vertical Precision Figure of Merit:</b> ").append(vPrecision).append(SEP); //NON-NLS
596  }
597 
598  String mapDatum = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_MAPDATUM);
599  if (mapDatum != null && !mapDatum.isEmpty()) {
600  result.append("<b>Map Datum:</b> ").append(mapDatum).append(SEP); //NON-NLS
601  }
602 
603  String programName = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME);
604  if (programName != null && !programName.isEmpty()) {
605  result.append("<b>Reported by:</b> ").append(programName).append(SEP); //NON-NLS
606  }
607 
608  String flag = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG);
609  if (flag != null && !flag.isEmpty()) {
610  result.append("<b>Flag:</b> ").append(flag).append(SEP); //NON-NLS
611  }
612 
613  String pathSource = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_SOURCE);
614  if (pathSource != null && !pathSource.isEmpty()) {
615  result.append("<b>Source:</b> ").append(pathSource).append(SEP); //NON-NLS
616  }
617 
618  String deviceMake = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE);
619  if (deviceMake != null && !deviceMake.isEmpty()) {
620  result.append("<b>Device Make:</b> ").append(deviceMake).append(SEP); //NON-NLS
621  }
622 
623  String deviceModel = getString(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL);
624  if (deviceModel != null && !deviceModel.isEmpty()) {
625  result.append("<b>Device Model:</b> ").append(deviceModel).append(SEP); //NON-NLS
626  }
627 
628  return result.toString();
629  }
630 
631  private String getTimeStamp(long timeStamp) {
632  return kmlDateFormat.format(new java.util.Date(timeStamp * 1000));
633  }
634 
648  private Element makePoint(Double latitude, Double longitude, Double altitude) {
649  if (latitude == null) {
650  latitude = 0.0;
651  }
652  if (longitude == null) {
653  longitude = 0.0;
654  }
655  if (altitude == null) {
656  altitude = 0.0;
657  }
658  Element point = new Element("Point", ns); //NON-NLS
659 
660  // KML uses lon, lat. Deliberately reversed.
661  Element coordinates = new Element("coordinates", ns).addContent(longitude + "," + latitude + "," + altitude); //NON-NLS
662 
663  if (altitude != 0) {
664  /*
665  Though we are including a non-zero altitude, clamp it to the
666  ground because inaccuracies from the GPS data can cause the terrain
667  to occlude points when zoomed in otherwise. Show the altitude, but
668  keep the point clamped to the ground. We may change this later for
669  flying GPS sensors.
670  */
671  Element altitudeMode = new Element("altitudeMode", ns).addContent("clampToGround"); //NON-NLS
672  point.addContent(altitudeMode);
673  }
674  point.addContent(coordinates);
675 
676  return point;
677  }
678 
696  private Element makeLineString(Double startLatitude, Double startLongitude, Double startAltitude, Double stopLatitude, Double stopLongitude, Double stopAltitude) {
697  if (startLatitude == null) {
698  startLatitude = 0.0;
699  }
700  if (startLongitude == null) {
701  startLongitude = 0.0;
702  }
703  if (startAltitude == null) {
704  startAltitude = 0.0;
705  }
706  if (stopLatitude == null) {
707  stopLatitude = 0.0;
708  }
709  if (stopLongitude == null) {
710  stopLongitude = 0.0;
711  }
712  if (stopAltitude == null) {
713  stopAltitude = 0.0;
714  }
715 
716  Element lineString = new Element("LineString", ns); //NON-NLS
717  lineString.addContent(new Element("extrude", ns).addContent("1")); //NON-NLS
718  lineString.addContent(new Element("tessellate", ns).addContent("1")); //NON-NLS
719  lineString.addContent(new Element("altitudeMode", ns).addContent("clampToGround")); //NON-NLS
720  // KML uses lon, lat. Deliberately reversed.
721  lineString.addContent(new Element("coordinates", ns).addContent(
722  startLongitude + "," + startLatitude + ",0.0,"
723  + stopLongitude + "," + stopLatitude + ",0.0")); //NON-NLS
724  return lineString;
725  }
726 
741  private Element makePlacemark(String name, FeatureColor color, String description, Long timestamp, Element feature, String coordinates) {
742  Element placemark = new Element("Placemark", ns); //NON-NLS
743  if (name != null && !name.isEmpty()) {
744  placemark.addContent(new Element("name", ns).addContent(name)); //NON-NLS
745  } else if (timestamp != null) {
746  placemark.addContent(new Element("name", ns).addContent(getTimeStamp(timestamp))); //NON-NLS
747  } else {
748  placemark.addContent(new Element("name", ns).addContent("")); //NON-NLS
749  }
750  placemark.addContent(new Element("styleUrl", ns).addContent(color.getColor())); //NON-NLS
751  placemark.addContent(new Element("description", ns).addContent(description)); //NON-NLS
752  if (timestamp != null) {
753  Element time = new Element("TimeStamp", ns); //NON-NLS
754  time.addContent(new Element("when", ns).addContent(getTimeStamp(timestamp))); //NON-NLS
755  placemark.addContent(time);
756  }
757  placemark.addContent(feature);
758  if (coordinates != null && !coordinates.isEmpty()) {
759  placemark.addContent(new Element("snippet", ns).addContent(coordinates)); //NON-NLS
760  }
761  return placemark;
762  }
763 
779  private Element makePlacemarkWithPicture(String name, FeatureColor color, String description, Long timestamp, Element feature, Path path, String coordinates) {
780  Element placemark = new Element("Placemark", ns); //NON-NLS
781  Element desc = new Element("description", ns); //NON-NLS
782  if (name != null && !name.isEmpty()) {
783  placemark.addContent(new Element("name", ns).addContent(name)); //NON-NLS
784  String image = "<img src='" + name + "' width='400'/>"; //NON-NLS
785  desc.addContent(image);
786  }
787  placemark.addContent(new Element("styleUrl", ns).addContent(color.getColor())); //NON-NLS
788  if (path != null) {
789  String pathAsString = path.toString();
790  if (pathAsString != null && !pathAsString.isEmpty()) {
791  desc.addContent(description + "<b>Source Path:</b> " + pathAsString);
792  }
793  }
794  placemark.addContent(desc);
795 
796  if (timestamp != null) {
797  Element time = new Element("TimeStamp", ns); //NON-NLS
798  time.addContent(new Element("when", ns).addContent(getTimeStamp(timestamp))); //NON-NLS
799  placemark.addContent(time);
800  }
801  placemark.addContent(feature);
802  if (coordinates != null && !coordinates.isEmpty()) {
803  placemark.addContent(new Element("snippet", ns).addContent(coordinates)); //NON-NLS
804  }
805  return placemark;
806  }
807 
816  private void copyFileUsingStream(AbstractFile inputFile, File outputFile) throws IOException {
817  byte[] buffer = new byte[65536];
818  int length;
819  outputFile.createNewFile();
820  try (InputStream is = new ReadContentInputStream(inputFile);
821  OutputStream os = new FileOutputStream(outputFile)) {
822  while ((length = is.read(buffer)) != -1) {
823  os.write(buffer, 0, length);
824  }
825  }
826  }
827 
828  @Override
829  public String getName() {
830  String name = NbBundle.getMessage(this.getClass(), "ReportKML.getName.text");
831  return name;
832  }
833 
834  @Override
835  public String getRelativeFilePath() {
836  return "ReportKML.kml"; //NON-NLS
837  }
838 
839  @Override
840  public String getDescription() {
841  String desc = NbBundle.getMessage(this.getClass(), "ReportKML.getDesc.text");
842  return desc;
843  }
844 
845  @Override
846  public JPanel getConfigurationPanel() {
847  return null; // No configuration panel
848  }
849 
860  private static String removeLeadingImgAndVol(String uniquePath) {
861  // split the path into parts
862  String[] pathSegments = uniquePath.replaceFirst("^/*", "").split("/"); //NON-NLS
863 
864  // Replace image/volume name if they exist in specific entries
865  if (pathSegments.length > 0) {
866  pathSegments[0] = pathSegments[0].replaceFirst("^img_", ""); //NON-NLS
867  }
868  if (pathSegments.length > 1) {
869  pathSegments[1] = pathSegments[1].replaceFirst("^vol_", ""); //NON-NLS
870  }
871 
872  // Assemble the path
873  StringBuilder strbuf = new StringBuilder();
874  for (String segment : pathSegments) {
875  if (!segment.isEmpty()) {
876  strbuf.append("/").append(segment);
877  }
878  }
879  return strbuf.toString();
880  }
881 }

Copyright © 2012-2016 Basis Technology. Generated on: Tue Feb 20 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.