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

Copyright © 2012-2018 Basis Technology. Generated on: Wed Sep 18 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.