Autopsy  4.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-15 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.io.File;
23 import java.io.FileWriter;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.Writer;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.time.LocalDateTime;
31 import java.util.function.Consumer;
32 import java.util.logging.Level;
33 import javafx.embed.swing.SwingFXUtils;
34 import javafx.event.ActionEvent;
35 import javafx.scene.Node;
36 import javafx.scene.control.Alert;
37 import javafx.scene.control.ButtonBar;
38 import javafx.scene.control.ButtonType;
39 import javafx.scene.image.Image;
40 import javafx.scene.image.ImageView;
41 import javafx.stage.Modality;
42 import javafx.stage.StageStyle;
43 import javax.imageio.ImageIO;
44 import javax.swing.JOptionPane;
45 import org.controlsfx.control.HyperlinkLabel;
46 import org.controlsfx.control.action.Action;
47 import org.openide.util.NbBundle;
53 import org.sleuthkit.datamodel.TskCoreException;
54 
58 public class SaveSnapshotAsReport extends Action {
59 
60  private static final Logger LOGGER = Logger.getLogger(SaveSnapshotAsReport.class.getName());
61  private static final Image SNAP_SHOT = new Image("org/sleuthkit/autopsy/timeline/images/image.png", 16, 16, true, true); // NON-NLS
62  private static final String HTML_EXT = ".html"; // NON-NLS
63  private static final String REPORT_IMAGE_EXTENSION = ".png"; // NON-NLS
64  private static final ButtonType open = new ButtonType(Bundle.OpenReportAction_DisplayName(), ButtonBar.ButtonData.NO);
65  private static final ButtonType ok = new ButtonType(ButtonType.OK.getText(), ButtonBar.ButtonData.CANCEL_CLOSE);
66 
67  @NbBundle.Messages({"SaveSnapshot.action.name.text=Snapshot Report",
68  "SaveSnapshot.action.longText=Save a screen capture of the visualization as a report.",
69  "SaveSnapshot.fileChoose.title.text=Save snapshot to",
70  "# {0} - report file path",
71  "SaveSnapShotAsReport.ReportSavedAt=Report saved at [{0}]",
72  "Timeline.ModuleName=Timeline", "SaveSnapShotAsReport.Success=Success",
73  "# {0} - uniqueness identifier, local date time at report creation time",
74  "SaveSnapsHotAsReport.ReportName=timeline-report-{0}",
75  "SaveSnapShotAsReport.FailedToAddReport=Failed to add snaphot as a report. See log for details",
76  "# {0} - report name",
77  "SaveSnapShotAsReport.ErrorWritingReport=Error writing report {0} to disk. See log for details",})
78  public SaveSnapshotAsReport(TimeLineController controller, Node node) {
79  super(Bundle.SaveSnapshot_action_name_text());
80  setLongText(Bundle.SaveSnapshot_action_longText());
81  setGraphic(new ImageView(SNAP_SHOT));
82  setEventHandler(new Consumer<ActionEvent>() {
83 
84  @Override
85  public void accept(ActionEvent actioneEvent) {
86  String escapedLocalDateTime = FileUtil.escapeFileName(LocalDateTime.now().toString());
87  String reportName = Bundle.SaveSnapsHotAsReport_ReportName(escapedLocalDateTime);
88  Path reportPath = Paths.get(Case.getCurrentCase().getReportDirectory(), reportName).toAbsolutePath();
89  File reportHTMLFIle = reportPath.resolve(reportName + HTML_EXT).toFile();
90 
91  ZoomParams zoomParams = controller.getEventsModel().zoomParametersProperty().get();
92 
93  try {
94  //ensure directory exists and write html file
95  Files.createDirectories(reportPath);
96  try (Writer htmlWriter = new FileWriter(reportHTMLFIle)) {
97  writeHTMLFile(reportName, htmlWriter, zoomParams);
98  }
99 
100  //take snapshot and save in report directory
101  ImageIO.write(SwingFXUtils.fromFXImage(node.snapshot(null, null), null), "png", // NON-NLS
102  reportPath.resolve(reportName + REPORT_IMAGE_EXTENSION).toFile()); // NON-NLS
103 
104  //copy report css
105  try (InputStream resource = this.getClass().getResourceAsStream("/org/sleuthkit/autopsy/timeline/index.css")) { // NON-NLS
106  Files.copy(resource, reportPath.resolve("index.css")); // NON-NLS
107  }
108 
109  //add html file as report to case
110  try {
111  Case.getCurrentCase().addReport(reportHTMLFIle.getPath(), Bundle.Timeline_ModuleName(), reportName + HTML_EXT); // NON-NLS
112  } catch (TskCoreException ex) {
113  LOGGER.log(Level.WARNING, "failed to add html wrapper as a report", ex); // NON-NLS
114  new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_FailedToAddReport()).showAndWait();
115  }
116 
117  //create alert to notify user of report location
118  final Alert alert = new Alert(Alert.AlertType.INFORMATION, null, open, ok);
119  alert.setTitle(Bundle.SaveSnapshot_action_name_text());
120  alert.setHeaderText(Bundle.SaveSnapShotAsReport_Success());
121  alert.initStyle(StageStyle.UTILITY);
122  alert.initOwner(node.getScene().getWindow());
123  alert.initModality(Modality.APPLICATION_MODAL);
124 
125  //make action to open report, and hyperlinklable to invoke action
126  final OpenReportAction openReportAction = new OpenReportAction(reportHTMLFIle);
127  HyperlinkLabel hyperlinkLabel = new HyperlinkLabel(Bundle.SaveSnapShotAsReport_ReportSavedAt(reportHTMLFIle.getPath()));
128  hyperlinkLabel.setOnAction(openReportAction);
129  alert.getDialogPane().setContent(hyperlinkLabel);
130 
131  alert.showAndWait().ifPresent(buttonType -> {
132  if (buttonType == open) {
133  openReportAction.handle(null);
134  }
135  });
136 
137  } catch (IOException e) {
138  LOGGER.log(Level.SEVERE, "Error writing report " + reportPath + " to disk", e); // NON-NLS
139  new Alert(Alert.AlertType.ERROR, Bundle.SaveSnapShotAsReport_ErrorWritingReport(reportPath)).showAndWait();
140  }
141  }
142  });
143  }
144 
145  private static void writeHTMLFile(String reportName, final Writer htmlWriter, ZoomParams zoomParams) throws IOException {
146 
147  //write html wrapper file
148  htmlWriter.write("<html>\n<head>\n\t<title>timeline snapshot</title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"index.css\" />\n</head>\n<body>\n"); // NON-NLS
149  htmlWriter.write("<div id=\"content\">\n<h1>" + reportName + "</h1>\n"); // NON-NLS
150  //embed snapshot
151  htmlWriter.write("<img src = \"" + reportName + REPORT_IMAGE_EXTENSION + "\" alt = \"snaphot\">"); // NON-NLS
152  //write view paramaters
153  htmlWriter.write("<table>\n"); // NON-NLS
154  writeTableRow(htmlWriter, "Case", Case.getCurrentCase().getName()); // NON-NLS
155  writeTableRow(htmlWriter, "Time Range", zoomParams.getTimeRange().toString()); // NON-NLS
156  writeTableRow(htmlWriter, "Description Level of Detail", zoomParams.getDescriptionLOD().getDisplayName()); // NON-NLS
157  writeTableRow(htmlWriter, "Event Type Zoom Level", zoomParams.getTypeZoomLevel().getDisplayName()); // NON-NLS
158  writeTableRow(htmlWriter, "Filters", zoomParams.getFilter().getHTMLReportString()); // NON-NLS
159  //end table and html
160  htmlWriter.write("</table>\n"); // NON-NLS
161  htmlWriter.write("</div>\n</body>\n</html>"); // NON-NLS
162  }
163 
172  private static void writeTableRow(final Writer htmlWriter, final String key, final String value) throws IOException {
173  htmlWriter.write("<tr><td>" + key + ": </td><td>" + value + "</td></tr>\n"); // NON-NLS
174  }
175 
176  @NbBundle.Messages({"OpenReportAction.DisplayName=Open Report",
177  "OpenReportAction.NoAssociatedEditorMessage=There is no associated editor for reports of this type or the associated application failed to launch.",
178  "OpenReportAction.MessageBoxTitle=Open Report Failure",
179  "OpenReportAction.NoOpenInEditorSupportMessage=This platform (operating system) does not support opening a file in an editor this way.",
180  "OpenReportAction.MissingReportFileMessage=The report file no longer exists.",
181  "OpenReportAction.ReportFileOpenPermissionDeniedMessage=Permission to open the report file was denied."})
182  private class OpenReportAction extends Action {
183 
184  OpenReportAction(File reportHTMLFIle) {
185  super(Bundle.OpenReportAction_DisplayName());
186  setEventHandler(actionEvent -> {
187  try {
188  Desktop.getDesktop().open(reportHTMLFIle);
189  } catch (IOException ex) {
190  JOptionPane.showMessageDialog(null,
191  Bundle.OpenReportAction_NoAssociatedEditorMessage(),
192  Bundle.OpenReportAction_MessageBoxTitle(),
193  JOptionPane.ERROR_MESSAGE);
194  } catch (UnsupportedOperationException ex) {
195  JOptionPane.showMessageDialog(null,
196  Bundle.OpenReportAction_NoOpenInEditorSupportMessage(),
197  Bundle.OpenReportAction_MessageBoxTitle(),
198  JOptionPane.ERROR_MESSAGE);
199  } catch (IllegalArgumentException ex) {
200  JOptionPane.showMessageDialog(null,
201  Bundle.OpenReportAction_MissingReportFileMessage(),
202  Bundle.OpenReportAction_MessageBoxTitle(),
203  JOptionPane.ERROR_MESSAGE);
204  } catch (SecurityException ex) {
205  JOptionPane.showMessageDialog(null,
206  Bundle.OpenReportAction_ReportFileOpenPermissionDeniedMessage(),
207  Bundle.OpenReportAction_MessageBoxTitle(),
208  JOptionPane.ERROR_MESSAGE);
209  }
210  });
211  }
212  }
213 }
static void writeTableRow(final Writer htmlWriter, final String key, final String value)
static void writeHTMLFile(String reportName, final Writer htmlWriter, ZoomParams zoomParams)
SaveSnapshotAsReport(TimeLineController controller, Node node)
synchronized ReadOnlyObjectProperty< ZoomParams > zoomParametersProperty()
void addReport(String localPath, String srcModuleName, String reportName)
Definition: Case.java:1687
static String escapeFileName(String fileName)
Definition: FileUtil.java:169
synchronized static Logger getLogger(String name)
Definition: Logger.java:166

Copyright © 2012-2015 Basis Technology. Generated on: Wed Apr 6 2016
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.