Autopsy  4.6.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
SaveSnapshotAsReport.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2014-2018 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.timeline.actions;
20 
21 import java.awt.Desktop;
22 import java.awt.image.BufferedImage;
23 import java.io.IOException;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.text.SimpleDateFormat;
28 import java.util.Date;
29 import java.util.function.Supplier;
30 import java.util.logging.Level;
31 import javafx.embed.swing.SwingFXUtils;
32 import javafx.scene.Node;
33 import javafx.scene.control.Alert;
34 import javafx.scene.control.ButtonBar;
35 import javafx.scene.control.ButtonType;
36 import javafx.scene.control.Control;
37 import javafx.scene.control.TextInputDialog;
38 import javafx.scene.image.Image;
39 import javafx.scene.image.ImageView;
40 import javax.swing.JOptionPane;
41 import org.apache.commons.lang3.StringUtils;
42 import org.controlsfx.control.HyperlinkLabel;
43 import org.controlsfx.control.action.Action;
44 import org.controlsfx.validation.ValidationResult;
45 import org.controlsfx.validation.ValidationSupport;
46 import org.controlsfx.validation.Validator;
47 import org.openide.util.NbBundle;
48 import org.openide.windows.WindowManager;
56 import org.sleuthkit.datamodel.TskCoreException;
57 
62 public class SaveSnapshotAsReport extends Action {
63 
64  private static final Logger LOGGER = Logger.getLogger(SaveSnapshotAsReport.class.getName());
65  private static final Image SNAP_SHOT = new Image("org/sleuthkit/autopsy/timeline/images/image.png", 16, 16, true, true); //NON_NLS
66  private static final ButtonType OPEN = new ButtonType(Bundle.OpenReportAction_DisplayName(), ButtonBar.ButtonData.NO);
67  private static final ButtonType OK = new ButtonType(ButtonType.OK.getText(), ButtonBar.ButtonData.CANCEL_CLOSE);
68 
70  private final Case currentCase;
71 
78  @NbBundle.Messages({
79  "Timeline.ModuleName=Timeline",
80  "SaveSnapShotAsReport.action.dialogs.title=Timeline",
81  "SaveSnapShotAsReport.action.name.text=Snapshot Report",
82  "SaveSnapShotAsReport.action.longText=Save a screen capture of the current view of the timeline as a report.",
83  "# {0} - report file path",
84  "SaveSnapShotAsReport.ReportSavedAt=Report saved at [{0}]",
85  "SaveSnapShotAsReport.Success=Success",
86  "SaveSnapShotAsReport.FailedToAddReport=Failed to add snaphot to case as a report.",
87  "# {0} - report path",
88  "SaveSnapShotAsReport.ErrorWritingReport=Error writing report to disk at {0}.",
89  "# {0} - generated default report name",
90  "SaveSnapShotAsReport.reportName.prompt=leave empty for default report name: {0}.",
91  "SaveSnapShotAsReport.reportName.header=Enter a report name for the Timeline Snapshot Report.",
92  "SaveSnapShotAsReport.duplicateReportNameError.text=A report with that name already exists."
93  })
94  public SaveSnapshotAsReport(TimeLineController controller, Supplier<Node> nodeSupplier) {
95  super(Bundle.SaveSnapShotAsReport_action_name_text());
96  setLongText(Bundle.SaveSnapShotAsReport_action_longText());
97  setGraphic(new ImageView(SNAP_SHOT));
98 
99  this.controller = controller;
100  this.currentCase = controller.getAutopsyCase();
101 
102  setEventHandler(actionEvent -> {
103  //capture generation date and use to make default report name
104  Date generationDate = new Date();
105  final String defaultReportName = FileUtil.escapeFileName(currentCase.getDisplayName() + " " + new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss").format(generationDate)); //NON_NLS
106  BufferedImage snapshot = SwingFXUtils.fromFXImage(nodeSupplier.get().snapshot(null, null), null);
107 
108  //prompt user to pick report name
109  TextInputDialog textInputDialog = new TextInputDialog();
110  PromptDialogManager.setDialogIcons(textInputDialog);
111  textInputDialog.setTitle(Bundle.SaveSnapShotAsReport_action_dialogs_title());
112  textInputDialog.getEditor().setPromptText(Bundle.SaveSnapShotAsReport_reportName_prompt(defaultReportName));
113  textInputDialog.setHeaderText(Bundle.SaveSnapShotAsReport_reportName_header());
114 
115  //keep prompt even if text field has focus, until user starts typing.
116  textInputDialog.getEditor().setStyle("-fx-prompt-text-fill: derive(-fx-control-inner-background, -30%);");//NON_NLS
117 
118  /*
119  * Create a ValidationSupport to validate that a report with the
120  * entered name doesn't exist on disk already. Disable ok button if
121  * report name is not validated.
122  */
123  ValidationSupport validationSupport = new ValidationSupport();
124  validationSupport.registerValidator(textInputDialog.getEditor(), false, new Validator<String>() {
125  @Override
126  public ValidationResult apply(Control textField, String enteredReportName) {
127  String reportName = StringUtils.defaultIfBlank(enteredReportName, defaultReportName);
128  boolean exists = Files.exists(Paths.get(currentCase.getReportDirectory(), reportName));
129  return ValidationResult.fromErrorIf(textField, Bundle.SaveSnapShotAsReport_duplicateReportNameError_text(), exists);
130  }
131  });
132  textInputDialog.getDialogPane().lookupButton(ButtonType.OK).disableProperty().bind(validationSupport.invalidProperty());
133 
134  //show dialog and handle result
135  textInputDialog.showAndWait().ifPresent(enteredReportName -> {
136  //reportName defaults to case name + timestamp if left blank
137  String reportName = StringUtils.defaultIfBlank(enteredReportName, defaultReportName);
138  Path reportFolderPath = Paths.get(currentCase.getReportDirectory(), reportName, "Timeline Snapshot"); //NON_NLS
139  Path reportMainFilePath;
140 
141  try {
142  //generate and write report
143  reportMainFilePath = new SnapShotReportWriter(currentCase,
144  reportFolderPath,
145  reportName,
146  controller.getEventsModel().getZoomParamaters(),
147  generationDate, snapshot).writeReport();
148  } catch (IOException ex) {
149  LOGGER.log(Level.SEVERE, "Error writing report to disk at " + reportFolderPath, ex); //NON_NLS
150  new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_ErrorWritingReport(reportFolderPath)).show();
151  return;
152  }
153 
154  try {
155  //add main file as report to case
156  Case.getOpenCase().addReport(reportMainFilePath.toString(), Bundle.Timeline_ModuleName(), reportName);
157  } catch (TskCoreException | NoCurrentCaseException ex) {
158  LOGGER.log(Level.WARNING, "Failed to add " + reportMainFilePath.toString() + " to case as a report", ex); //NON_NLS
159  new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_FailedToAddReport()).show();
160  return;
161  }
162 
163  //notify user of report location
164  final Alert alert = new Alert(Alert.AlertType.INFORMATION, null, OPEN, OK);
165  alert.setTitle(Bundle.SaveSnapShotAsReport_action_dialogs_title());
166  alert.setHeaderText(Bundle.SaveSnapShotAsReport_Success());
167 
168  //make action to open report, and hyperlinklable to invoke action
169  final OpenReportAction openReportAction = new OpenReportAction(reportMainFilePath);
170  HyperlinkLabel hyperlinkLabel = new HyperlinkLabel(Bundle.SaveSnapShotAsReport_ReportSavedAt(reportMainFilePath.toString()));
171  hyperlinkLabel.setOnAction(openReportAction);
172  alert.getDialogPane().setContent(hyperlinkLabel);
173 
174  alert.showAndWait().filter(OPEN::equals).ifPresent(buttonType -> openReportAction.handle(null));
175  });
176  });
177  }
178 
182  @NbBundle.Messages({
183  "OpenReportAction.DisplayName=Open Report",
184  "OpenReportAction.NoAssociatedEditorMessage=There is no associated editor for reports of this type or the associated application failed to launch.",
185  "OpenReportAction.MessageBoxTitle=Open Report Failure",
186  "OpenReportAction.NoOpenInEditorSupportMessage=This platform (operating system) does not support opening a file in an editor this way.",
187  "OpenReportAction.MissingReportFileMessage=The report file no longer exists.",
188  "OpenReportAction.ReportFileOpenPermissionDeniedMessage=Permission to open the report file was denied."})
189  private class OpenReportAction extends Action {
190 
191  OpenReportAction(Path reportHTMLFIle) {
192  super(Bundle.OpenReportAction_DisplayName());
193  setEventHandler(actionEvent -> {
194  try {
195  Desktop.getDesktop().open(reportHTMLFIle.toFile());
196  } catch (IOException ex) {
197  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
198  Bundle.OpenReportAction_NoAssociatedEditorMessage(),
199  Bundle.OpenReportAction_MessageBoxTitle(),
200  JOptionPane.ERROR_MESSAGE);
201  } catch (UnsupportedOperationException ex) {
202  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
203  Bundle.OpenReportAction_NoOpenInEditorSupportMessage(),
204  Bundle.OpenReportAction_MessageBoxTitle(),
205  JOptionPane.ERROR_MESSAGE);
206  } catch (IllegalArgumentException ex) {
207  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
208  Bundle.OpenReportAction_MissingReportFileMessage(),
209  Bundle.OpenReportAction_MessageBoxTitle(),
210  JOptionPane.ERROR_MESSAGE);
211  } catch (SecurityException ex) {
212  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
213  Bundle.OpenReportAction_ReportFileOpenPermissionDeniedMessage(),
214  Bundle.OpenReportAction_MessageBoxTitle(),
215  JOptionPane.ERROR_MESSAGE);
216  }
217  });
218  }
219  }
220 }
void addReport(String localPath, String srcModuleName, String reportName)
Definition: Case.java:1549
SaveSnapshotAsReport(TimeLineController controller, Supplier< Node > nodeSupplier)
static String escapeFileName(String fileName)
Definition: FileUtil.java:169
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

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