Autopsy  4.13.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
GeolocationTopComponent.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.geolocation;
20 
21 import java.awt.BorderLayout;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.beans.PropertyChangeEvent;
25 import java.beans.PropertyChangeListener;
26 import java.io.File;
27 import java.io.IOException;
28 import java.text.DateFormat;
29 import java.text.SimpleDateFormat;
30 import java.util.ArrayList;
31 import java.util.Date;
32 import java.util.EnumSet;
33 import java.util.List;
34 import java.util.Locale;
35 import java.util.Set;
36 import java.util.logging.Level;
37 import javax.swing.JOptionPane;
38 import javax.swing.SwingUtilities;
39 import javax.swing.SwingWorker;
40 import org.openide.filesystems.FileUtil;
41 import org.openide.util.NbBundle.Messages;
42 import org.openide.windows.RetainLocation;
43 import org.openide.windows.TopComponent;
44 import org.openide.windows.WindowManager;
60 import org.sleuthkit.datamodel.BlackboardArtifact;
61 
66 @TopComponent.Description(preferredID = "GeolocationTopComponent", persistenceType = TopComponent.PERSISTENCE_NEVER)
67 @TopComponent.Registration(mode = "geolocation", openAtStartup = false)
68 @RetainLocation("geolocation")
69 @SuppressWarnings("PMD.SingularField")
70 public final class GeolocationTopComponent extends TopComponent {
71 
72  private static final long serialVersionUID = 1L;
73 
74  private static final Logger logger = Logger.getLogger(GeolocationTopComponent.class.getName());
75 
76  private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED);
77 
78  private final PropertyChangeListener ingestListener;
79  private final PropertyChangeListener caseEventListener;
80  private final GeoFilterPanel geoFilterPanel;
81 
82  final RefreshPanel refreshPanel = new RefreshPanel();
83 
84  private static final String REPORT_PATH_FMT_STR = "%s" + File.separator + "%s %s %s" + File.separator;
85 
86  // This is the hardcoded report name from KMLReport.java
87  private static final String REPORT_KML = "ReportKML.kml";
88 
89  private boolean mapInitalized = false;
90 
91  @Messages({
92  "GLTopComponent_name=Geolocation",
93  "GLTopComponent_initilzation_error=An error occurred during waypoint initilization. Geolocation data maybe incomplete."
94  })
95 
101  initComponents();
102 
103  setName(Bundle.GLTopComponent_name());
104 
105  this.ingestListener = pce -> {
106  String eventType = pce.getPropertyName();
107  if (eventType.equals(DATA_ADDED.toString())) {
108  // Indicate that a refresh may be needed for GPS data.
109  ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue();
110  if (null != eventData
111  && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID()
112  || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID()
113  || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID()
114  || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID()
115  || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()
116  || eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID())) {
117 
118  showRefreshPanel(true);
119  }
120  }
121  };
122 
123  this.caseEventListener = pce -> {
124  mapPanel.clearWaypoints();
125  if (pce.getNewValue() != null) {
126  updateWaypoints();
127  }
128  };
129 
130  refreshPanel.addCloseActionListener(new ActionListener() {
131  @Override
132  public void actionPerformed(ActionEvent e) {
133  showRefreshPanel(false);
134  }
135  });
136 
137  refreshPanel.addRefreshActionListner(new ActionListener() {
138  @Override
139  public void actionPerformed(ActionEvent e) {
140  geoFilterPanel.updateDataSourceList();
141  mapPanel.clearWaypoints();
142  updateWaypoints();
143  showRefreshPanel(false);
144  }
145  });
146 
147  geoFilterPanel = new GeoFilterPanel();
148  filterPane.setPanel(geoFilterPanel);
149  geoFilterPanel.addActionListener(new ActionListener() {
150  @Override
151  public void actionPerformed(ActionEvent e) {
152  updateWaypoints();
153  }
154  });
155 
156  mapPanel.addPropertyChangeListener(MapPanel.CURRENT_MOUSE_GEOPOSITION, new PropertyChangeListener() {
157  @Override
158  public void propertyChange(PropertyChangeEvent evt) {
159  String label = "";
160  Object newValue = evt.getNewValue();
161  if (newValue != null) {
162  label = newValue.toString();
163  }
164 
165  coordLabel.setText(label);
166  }
167 
168  });
169  }
170 
171  @Override
172  public void addNotify() {
173  super.addNotify();
174  IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, ingestListener);
175  Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), caseEventListener);
176  }
177 
178  @Override
179  public void removeNotify() {
180  super.removeNotify();
182  Case.removeEventTypeSubscriber(EnumSet.of(CURRENT_CASE), caseEventListener);
183  }
184 
185  @Override
186  public void componentOpened() {
187  super.componentOpened();
188  WindowManager.getDefault().setTopComponentFloating(this, true);
189 
190  }
191 
192  @Messages({
193  "GeolocationTC_connection_failure_message=Failed to connect to map title source.\nPlease review map source in Options dialog.",
194  "GeolocationTC_connection_failure_message_title=Connection Failure"
195  })
196  @Override
197  public void open() {
198  super.open();
199  mapPanel.clearWaypoints();
200  geoFilterPanel.clearDataSourceList();
201  geoFilterPanel.updateDataSourceList();
202 
203  // Let's make sure we only do this on the first open
204  if (!mapInitalized) {
205  try {
206  mapPanel.initMap();
207  mapInitalized = true;
208  } catch (GeoLocationDataException ex) {
209  JOptionPane.showMessageDialog(this,
210  Bundle.GeolocationTC_connection_failure_message(),
211  Bundle.GeolocationTC_connection_failure_message_title(),
212  JOptionPane.ERROR_MESSAGE);
214  Bundle.GeolocationTC_connection_failure_message_title(),
215  Bundle.GeolocationTC_connection_failure_message());
216  logger.log(Level.SEVERE, ex.getMessage(), ex);
217  return; // Doen't set the waypoints.
218  }
219  }
220  mapPanel.setWaypoints(new ArrayList<>());
221  updateWaypoints();
222  }
223 
229  private void showRefreshPanel(boolean show) {
230  if (show) {
231  mapPanel.add(refreshPanel, BorderLayout.NORTH);
232  } else {
233  mapPanel.remove(refreshPanel);
234  }
235  mapPanel.revalidate();
236  }
237 
242  @Messages({
243  "GeoTopComponent_no_waypoints_returned_mgs=Applied filter failed to find waypoints that matched criteria.\nRevise filter options and try again.",
244  "GeoTopComponent_no_waypoints_returned_Title=No Waypoints Found",
245  "GeoTopComponent_filter_exception_msg=Exception occured during waypoint filtering.",
246  "GeoTopComponent_filter_exception_Title=Filter Failure",
247  "GeoTopComponent_filer_data_invalid_msg=Unable to run waypoint filter.\nPlease select one or more data sources.",
248  "GeoTopComponent_filer_data_invalid_Title=Filter Failure"
249  })
250  private void updateWaypoints() {
251  GeoFilter filters;
252 
253  // Show a warning message if the user has not selected a data source
254  try {
255  filters = geoFilterPanel.getFilterState();
256  } catch (GeoLocationUIException ex) {
257  JOptionPane.showMessageDialog(this,
258  Bundle.GeoTopComponent_filer_data_invalid_msg(),
259  Bundle.GeoTopComponent_filer_data_invalid_Title(),
260  JOptionPane.INFORMATION_MESSAGE);
261  return;
262  }
263 
264  setWaypointLoading(true);
265  geoFilterPanel.setEnabled(false);
266 
267  Thread thread = new Thread(new WaypointRunner(filters));
268  thread.start();
269  }
270 
276  void setWaypointLoading(boolean loading) {
277  progressBar.setEnabled(true);
278  progressBar.setVisible(loading);
279  progressBar.setString("Loading Waypoints");
280  }
281 
292  private static String createReportDirectory() throws IOException {
293  Case currentCase = Case.getCurrentCase();
294 
295  // Create the root reports directory path of the form: <CASE DIRECTORY>/Reports/<Case fileName> <Timestamp>/
296  DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss", Locale.US);
297  Date date = new Date();
298  String dateNoTime = dateFormat.format(date);
299  String reportPath = String.format(REPORT_PATH_FMT_STR, currentCase.getReportDirectory(), currentCase.getDisplayName(), "Google Earth KML", dateNoTime);
300  // Create the root reports directory.
301  try {
302  FileUtil.createFolder(new File(reportPath));
303  } catch (IOException ex) {
304  throw new IOException("Failed to make report folder, unable to generate reports.", ex);
305  }
306  return reportPath;
307  }
308 
314  @SuppressWarnings("unchecked")
315  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
316  private void initComponents() {
317  java.awt.GridBagConstraints gridBagConstraints;
318 
319  filterPane = new org.sleuthkit.autopsy.geolocation.HidingPane();
320  statusBar = new javax.swing.JPanel();
321  reportButton = new javax.swing.JButton();
322  progressBar = new javax.swing.JProgressBar();
323  coordLabel = new javax.swing.JLabel();
324  mapPanel = new org.sleuthkit.autopsy.geolocation.MapPanel();
325 
326  setLayout(new java.awt.BorderLayout());
327  add(filterPane, java.awt.BorderLayout.WEST);
328 
329  statusBar.setLayout(new java.awt.GridBagLayout());
330 
331  org.openide.awt.Mnemonics.setLocalizedText(reportButton, org.openide.util.NbBundle.getMessage(GeolocationTopComponent.class, "GeolocationTopComponent.reportButton.text")); // NOI18N
332  reportButton.addActionListener(new java.awt.event.ActionListener() {
333  public void actionPerformed(java.awt.event.ActionEvent evt) {
334  reportButtonActionPerformed(evt);
335  }
336  });
337  gridBagConstraints = new java.awt.GridBagConstraints();
338  gridBagConstraints.gridx = 2;
339  gridBagConstraints.gridy = 0;
340  gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
341  gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
342  statusBar.add(reportButton, gridBagConstraints);
343 
344  progressBar.setIndeterminate(true);
345  gridBagConstraints = new java.awt.GridBagConstraints();
346  gridBagConstraints.gridx = 1;
347  gridBagConstraints.gridy = 0;
348  gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
349  statusBar.add(progressBar, gridBagConstraints);
350 
351  org.openide.awt.Mnemonics.setLocalizedText(coordLabel, org.openide.util.NbBundle.getMessage(GeolocationTopComponent.class, "GeolocationTopComponent.coordLabel.text")); // NOI18N
352  gridBagConstraints = new java.awt.GridBagConstraints();
353  gridBagConstraints.gridx = 0;
354  gridBagConstraints.gridy = 0;
355  gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
356  gridBagConstraints.weightx = 1.0;
357  gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0);
358  statusBar.add(coordLabel, gridBagConstraints);
359 
360  add(statusBar, java.awt.BorderLayout.SOUTH);
361  add(mapPanel, java.awt.BorderLayout.CENTER);
362  }// </editor-fold>//GEN-END:initComponents
363 
364  @Messages({
365  "GeolocationTC_empty_waypoint_message=Unable to generate KML report due to a lack of waypoints.\nPlease make sure there are waypoints visible before generating the KML report",
366  "GeolocationTC_KML_report_title=KML Report",
367  "GeolocationTC_report_progress_title=KML Report Progress"
368  })
369  private void reportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reportButtonActionPerformed
370  List<MapWaypoint> visiblePoints = mapPanel.getVisibleWaypoints();
371  if (visiblePoints.isEmpty()) {
372  JOptionPane.showConfirmDialog(this, Bundle.GeolocationTC_empty_waypoint_message(), Bundle.GeolocationTC_KML_report_title(), JOptionPane.OK_OPTION, JOptionPane.INFORMATION_MESSAGE);
373  return;
374  }
375 
376  try {
377  ReportProgressPanel progressPanel = new ReportProgressPanel();
378  String reportBaseDir = createReportDirectory();
379 
380  progressPanel.setLabels(REPORT_KML, reportBaseDir);
381 
382  SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
383  @Override
384  protected Void doInBackground() throws Exception {
385  KMLReport.getDefault().generateReport(reportBaseDir, progressPanel, MapWaypoint.getDataModelWaypoints(visiblePoints));
386  return null;
387  }
388  };
389  worker.execute();
390  JOptionPane.showConfirmDialog(this, progressPanel, Bundle.GeolocationTC_report_progress_title(), JOptionPane.CLOSED_OPTION, JOptionPane.PLAIN_MESSAGE);
391  } catch (IOException ex) {
392  logger.log(Level.WARNING, "Unable to create KML report", ex);
393  }
394  }//GEN-LAST:event_reportButtonActionPerformed
395 
396 
397  // Variables declaration - do not modify//GEN-BEGIN:variables
398  private javax.swing.JLabel coordLabel;
401  private javax.swing.JProgressBar progressBar;
402  private javax.swing.JButton reportButton;
403  private javax.swing.JPanel statusBar;
404  // End of variables declaration//GEN-END:variables
405 
409  private class WaypointRunner implements Runnable {
410 
411  private final GeoFilter filters;
412 
418  WaypointRunner(GeoFilter filters) {
419  this.filters = filters;
420  }
421 
422  @Override
423  public void run() {
424  Case currentCase = Case.getCurrentCase();
425  try {
427  filters.getDataSources(),
428  filters.showAllWaypoints(),
429  filters.getMostRecentNumDays(),
430  filters.showWaypointsWithoutTimeStamp(),
431  new WaypointCallBack());
432 
433  } catch (GeoLocationDataException ex) {
434  logger.log(Level.SEVERE, "Failed to filter waypoints.", ex);
435  SwingUtilities.invokeLater(new Runnable() {
436  @Override
437  public void run() {
438  JOptionPane.showMessageDialog(GeolocationTopComponent.this,
439  Bundle.GeoTopComponent_filter_exception_Title(),
440  Bundle.GeoTopComponent_filter_exception_msg(),
441  JOptionPane.ERROR_MESSAGE);
442 
443  setWaypointLoading(false);
444  }
445  });
446  }
447  }
448 
449  }
450 
455 
456  @Override
457  public void process(final List<Waypoint> waypoints) {
458  // Make sure that the waypoints are added to the map panel in
459  // the correct thread.
460  SwingUtilities.invokeLater(new Runnable() {
461  @Override
462  public void run() {
463  // If the list is empty, tell the user and do not change
464  // the visible waypoints.
465  if (waypoints == null || waypoints.isEmpty()) {
466  mapPanel.clearWaypoints();
467  JOptionPane.showMessageDialog(GeolocationTopComponent.this,
468  Bundle.GeoTopComponent_no_waypoints_returned_Title(),
469  Bundle.GeoTopComponent_no_waypoints_returned_mgs(),
470  JOptionPane.INFORMATION_MESSAGE);
471  setWaypointLoading(false);
472  geoFilterPanel.setEnabled(true);
473  return;
474  }
475  mapPanel.clearWaypoints();
476  mapPanel.setWaypoints(MapWaypoint.getWaypoints(waypoints));
477  setWaypointLoading(false);
478  geoFilterPanel.setEnabled(true);
479  }
480  });
481  }
482  }
483 }
final void setLabels(String reportName, String reportPath)
BlackboardArtifact.Type getBlackboardArtifactType()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static synchronized IngestManager getInstance()
static List< Waypoint > getAllWaypoints(SleuthkitCase skCase)
static synchronized KMLReport getDefault()
Definition: KMLReport.java:108
void generateReport(String baseReportDir, ReportProgressPanel progressPanel, List< Waypoint > waypointList)
Definition: KMLReport.java:148
static void error(String title, String message)
void addIngestModuleEventListener(final PropertyChangeListener listener)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:486
org.sleuthkit.autopsy.geolocation.HidingPane filterPane
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:531

Copyright © 2012-2019 Basis Technology. Generated on: Tue Jan 7 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.