Autopsy  4.10.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
CaseUcoFormatExporter.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2018-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.report.caseuco;
20 
21 import com.fasterxml.jackson.core.JsonEncoding;
22 import com.fasterxml.jackson.core.JsonFactory;
23 import com.fasterxml.jackson.core.JsonGenerator;
24 import com.fasterxml.jackson.core.util.DefaultIndenter;
25 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
26 import java.io.IOException;
27 import java.nio.file.Files;
28 import java.nio.file.Paths;
29 import java.sql.ResultSet;
30 import java.sql.SQLException;
31 import java.util.SimpleTimeZone;
32 import java.util.logging.Level;
33 import org.openide.util.NbBundle;
41 import org.sleuthkit.datamodel.SleuthkitCase;
42 import org.sleuthkit.datamodel.TskCoreException;
43 import org.sleuthkit.datamodel.TskData;
44 
48 public final class CaseUcoFormatExporter {
49 
50  private static final Logger logger = Logger.getLogger(CaseUcoFormatExporter.class.getName());
51 
53  }
54 
63  @NbBundle.Messages({
64  "ReportCaseUco.noCaseOpen=Unable to open currect case",
65  "ReportCaseUco.unableToCreateDirectories=Unable to create directory for CASE-UCO report",
66  "ReportCaseUco.initializing=Creating directories...",
67  "ReportCaseUco.querying=Querying files...",
68  "ReportCaseUco.ingestWarning=Warning, this report will be created before ingest services completed",
69  "ReportCaseUco.processing=Saving files in CASE-UCO format...",
70  "ReportCaseUco.srcModuleName.text=CASE-UCO Report"
71  })
72  @SuppressWarnings("deprecation")
73  public static void generateReport(Long selectedDataSourceId, String reportOutputPath, ReportProgressPanel progressPanel) {
74 
75  // Start the progress bar and setup the report
76  progressPanel.setIndeterminate(false);
77  progressPanel.start();
78  progressPanel.updateStatusLabel(Bundle.ReportCaseUco_initializing());
79 
80  // Create the JSON generator
81  JsonFactory jsonGeneratorFactory = new JsonFactory();
82  java.io.File reportFile = Paths.get(reportOutputPath).toFile();
83  try {
84  Files.createDirectories(Paths.get(reportFile.getParent()));
85  } catch (IOException ex) {
86  logger.log(Level.SEVERE, "Unable to create directory for CASE-UCO report", ex); //NON-NLS
87  MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_unableToCreateDirectories());
89  return;
90  }
91 
92  // Check if ingest has finished
94  MessageNotifyUtil.Message.warn(Bundle.ReportCaseUco_ingestWarning());
95  }
96 
97  JsonGenerator jsonGenerator = null;
98  SimpleTimeZone timeZone = new SimpleTimeZone(0, "GMT");
99  try {
100  jsonGenerator = jsonGeneratorFactory.createGenerator(reportFile, JsonEncoding.UTF8);
101  // instert \n after each field for more readable formatting
102  jsonGenerator.setPrettyPrinter(new DefaultPrettyPrinter().withObjectIndenter(new DefaultIndenter(" ", "\n")));
103 
104  SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
105 
106  progressPanel.updateStatusLabel(Bundle.ReportCaseUco_querying());
107 
108  // create the required CASE-UCO entries at the beginning of the output file
109  initializeJsonOutputFile(jsonGenerator);
110 
111  // create CASE-UCO entry for the Autopsy case
112  String caseTraceId = saveCaseInfo(skCase, jsonGenerator);
113 
114  // create CASE-UCO data source entry
115  String dataSourceTraceId = saveDataSourceInfo(selectedDataSourceId, caseTraceId, skCase, jsonGenerator);
116 
117  // Run getAllFilesQuery to get all files, exclude directories
118  final String getAllFilesQuery = "select obj_id, name, size, crtime, atime, mtime, md5, parent_path, mime_type, extension from tsk_files where "
119  + "data_source_obj_id = " + Long.toString(selectedDataSourceId)
120  + " AND ((meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_UNDEF.getValue()
121  + ") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
122  + ") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT.getValue() + "))"; //NON-NLS
123 
124  try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getAllFilesQuery)) {
125  ResultSet resultSet = queryResult.getResultSet();
126 
127  progressPanel.updateStatusLabel(Bundle.ReportCaseUco_processing());
128 
129  // Loop files and write info to CASE-UCO report
130  while (resultSet.next()) {
131 
132  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
133  break;
134  }
135 
136  Long objectId = resultSet.getLong(1);
137  String fileName = resultSet.getString(2);
138  long size = resultSet.getLong("size");
139  String crtime = ContentUtils.getStringTimeISO8601(resultSet.getLong("crtime"), timeZone);
140  String atime = ContentUtils.getStringTimeISO8601(resultSet.getLong("atime"), timeZone);
141  String mtime = ContentUtils.getStringTimeISO8601(resultSet.getLong("mtime"), timeZone);
142  String md5Hash = resultSet.getString("md5");
143  String parent_path = resultSet.getString("parent_path");
144  String mime_type = resultSet.getString("mime_type");
145  String extension = resultSet.getString("extension");
146 
147  saveFileInCaseUcoFormat(objectId, fileName, parent_path, md5Hash, mime_type, size, crtime, atime, mtime, extension, jsonGenerator, dataSourceTraceId);
148  }
149  }
150 
151  // create the required CASE-UCO entries at the end of the output file
152  finilizeJsonOutputFile(jsonGenerator);
153 
154  Case.getCurrentCaseThrows().addReport(reportOutputPath, Bundle.ReportCaseUco_srcModuleName_text(), "");
155 
157  } catch (TskCoreException ex) {
158  logger.log(Level.SEVERE, "Failed to get list of files from case database", ex); //NON-NLS
160  } catch (IOException ex) {
161  logger.log(Level.SEVERE, "Failed to create JSON output for the CASE-UCO report", ex); //NON-NLS
163  } catch (SQLException ex) {
164  logger.log(Level.WARNING, "Unable to read result set", ex); //NON-NLS
166  } catch (NoCurrentCaseException ex) {
167  logger.log(Level.SEVERE, "No current case open", ex); //NON-NLS
169  } finally {
170  if (jsonGenerator != null) {
171  try {
172  jsonGenerator.close();
173  } catch (IOException ex) {
174  logger.log(Level.WARNING, "Failed to close JSON output file", ex); //NON-NLS
175  }
176  }
177  }
178  }
179 
180  private static void initializeJsonOutputFile(JsonGenerator catalog) throws IOException {
181  catalog.writeStartObject();
182  catalog.writeFieldName("@graph");
183  catalog.writeStartArray();
184  }
185 
186  private static void finilizeJsonOutputFile(JsonGenerator catalog) throws IOException {
187  catalog.writeEndArray();
188  catalog.writeEndObject();
189  }
190 
202  private static String saveCaseInfo(SleuthkitCase skCase, JsonGenerator catalog) throws TskCoreException, SQLException, IOException, NoCurrentCaseException {
203 
204  // create a "trace" entry for the Autopsy case iteself
205  String uniqueCaseName;
206  String dbFileName;
207  TskData.DbType dbType = skCase.getDatabaseType();
208  if (dbType == TskData.DbType.SQLITE) {
209  uniqueCaseName = Case.getCurrentCaseThrows().getName();
210  dbFileName = skCase.getDatabaseName();
211  } else {
212  uniqueCaseName = skCase.getDatabaseName();
213  dbFileName = "";
214  }
215 
216  String caseDirPath = skCase.getDbDirPath();
217  String caseTraceId = "case-" + uniqueCaseName;
218  catalog.writeStartObject();
219  catalog.writeStringField("@id", caseTraceId);
220  catalog.writeStringField("@type", "Trace");
221 
222  catalog.writeFieldName("propertyBundle");
223  catalog.writeStartArray();
224  catalog.writeStartObject();
225 
226  // replace double slashes with single ones
227  caseDirPath = caseDirPath.replaceAll("\\\\", "/");
228 
229  catalog.writeStringField("@type", "File");
230  if (dbType == TskData.DbType.SQLITE) {
231  catalog.writeStringField("filePath", caseDirPath + "/" + dbFileName);
232  catalog.writeBooleanField("isDirectory", false);
233  } else {
234  catalog.writeStringField("filePath", caseDirPath);
235  catalog.writeBooleanField("isDirectory", true);
236  }
237  catalog.writeEndObject();
238 
239  catalog.writeEndArray();
240  catalog.writeEndObject();
241 
242  return caseTraceId;
243  }
244 
257  private static String saveDataSourceInfo(Long selectedDataSourceId, String caseTraceId, SleuthkitCase skCase, JsonGenerator jsonGenerator) throws TskCoreException, SQLException, IOException {
258 
259  Long imageSize = (long) 0;
260  String imageName = "";
261  boolean isImageDataSource = false;
262  String getImageDataSourceQuery = "select size from tsk_image_info where obj_id = " + selectedDataSourceId;
263  try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getImageDataSourceQuery)) {
264  ResultSet resultSet = queryResult.getResultSet();
265  // check if we got a result
266  while (resultSet.next()) {
267  // we got a result so the data source was an image data source
268  imageSize = resultSet.getLong(1);
269  isImageDataSource = true;
270  break;
271  }
272  }
273 
274  if (isImageDataSource) {
275  // get caseDirPath to image file
276  String getPathToDataSourceQuery = "select name from tsk_image_names where obj_id = " + selectedDataSourceId;
277  try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getPathToDataSourceQuery)) {
278  ResultSet resultSet = queryResult.getResultSet();
279  while (resultSet.next()) {
280  imageName = resultSet.getString(1);
281  break;
282  }
283  }
284  } else {
285  // logical file data source
286  String getLogicalDataSourceQuery = "select name from tsk_files where obj_id = " + selectedDataSourceId;
287  try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getLogicalDataSourceQuery)) {
288  ResultSet resultSet = queryResult.getResultSet();
289  while (resultSet.next()) {
290  imageName = resultSet.getString(1);
291  break;
292  }
293  }
294  }
295 
296  return saveDataSourceInCaseUcoFormat(jsonGenerator, imageName, imageSize, selectedDataSourceId, caseTraceId);
297  }
298 
299  private static String saveDataSourceInCaseUcoFormat(JsonGenerator catalog, String imageName, Long imageSize, Long selectedDataSourceId, String caseTraceId) throws IOException {
300 
301  // create a "trace" entry for the data source
302  String dataSourceTraceId = "data-source-" + selectedDataSourceId;
303  catalog.writeStartObject();
304  catalog.writeStringField("@id", dataSourceTraceId);
305  catalog.writeStringField("@type", "Trace");
306 
307  catalog.writeFieldName("propertyBundle");
308  catalog.writeStartArray();
309 
310  catalog.writeStartObject();
311  catalog.writeStringField("@type", "File");
312 
313  // replace double back slashes with single ones
314  imageName = imageName.replaceAll("\\\\", "/");
315 
316  catalog.writeStringField("filePath", imageName);
317  catalog.writeEndObject();
318 
319  if (imageSize > 0) {
320  catalog.writeStartObject();
321  catalog.writeStringField("@type", "ContentData");
322  catalog.writeStringField("sizeInBytes", Long.toString(imageSize));
323  catalog.writeEndObject();
324  }
325 
326  catalog.writeEndArray();
327  catalog.writeEndObject();
328 
329  // create a "relationship" entry between the case and the data source
330  catalog.writeStartObject();
331  catalog.writeStringField("@id", "relationship-" + caseTraceId);
332  catalog.writeStringField("@type", "Relationship");
333  catalog.writeStringField("source", dataSourceTraceId);
334  catalog.writeStringField("target", caseTraceId);
335  catalog.writeStringField("kindOfRelationship", "contained-within");
336  catalog.writeBooleanField("isDirectional", true);
337 
338  catalog.writeFieldName("propertyBundle");
339  catalog.writeStartArray();
340  catalog.writeStartObject();
341  catalog.writeStringField("@type", "PathRelation");
342  catalog.writeStringField("path", imageName);
343  catalog.writeEndObject();
344  catalog.writeEndArray();
345 
346  catalog.writeEndObject();
347 
348  return dataSourceTraceId;
349  }
350 
351  private static void saveFileInCaseUcoFormat(Long objectId, String fileName, String parent_path, String md5Hash, String mime_type, long size, String ctime,
352  String atime, String mtime, String extension, JsonGenerator catalog, String dataSourceTraceId) throws IOException {
353 
354  String fileTraceId = "file-" + objectId;
355 
356  // create a "trace" entry for the file
357  catalog.writeStartObject();
358  catalog.writeStringField("@id", fileTraceId);
359  catalog.writeStringField("@type", "Trace");
360 
361  catalog.writeFieldName("propertyBundle");
362  catalog.writeStartArray();
363 
364  catalog.writeStartObject();
365  catalog.writeStringField("@type", "File");
366  catalog.writeStringField("createdTime", ctime);
367  catalog.writeStringField("accessedTime", atime);
368  catalog.writeStringField("modifiedTime", mtime);
369  if (extension != null) {
370  catalog.writeStringField("extension", extension);
371  }
372  catalog.writeStringField("fileName", fileName);
373  if (parent_path != null) {
374  catalog.writeStringField("filePath", parent_path + fileName);
375  }
376  catalog.writeBooleanField("isDirectory", false);
377  catalog.writeStringField("sizeInBytes", Long.toString(size));
378  catalog.writeEndObject();
379 
380  catalog.writeStartObject();
381  catalog.writeStringField("@type", "ContentData");
382  if (mime_type != null) {
383  catalog.writeStringField("mimeType", mime_type);
384  }
385  if (md5Hash != null) {
386  catalog.writeFieldName("hash");
387  catalog.writeStartArray();
388  catalog.writeStartObject();
389  catalog.writeStringField("@type", "Hash");
390  catalog.writeStringField("hashMethod", "MD5");
391  catalog.writeStringField("hashValue", md5Hash);
392  catalog.writeEndObject();
393  catalog.writeEndArray();
394  }
395  catalog.writeStringField("sizeInBytes", Long.toString(size));
396 
397  catalog.writeEndObject();
398 
399  catalog.writeEndArray();
400  catalog.writeEndObject();
401 
402  // create a "relationship" entry between the file and the data source
403  catalog.writeStartObject();
404  catalog.writeStringField("@id", "relationship-" + objectId);
405  catalog.writeStringField("@type", "Relationship");
406  catalog.writeStringField("source", fileTraceId);
407  catalog.writeStringField("target", dataSourceTraceId);
408  catalog.writeStringField("kindOfRelationship", "contained-within");
409  catalog.writeBooleanField("isDirectional", true);
410 
411  catalog.writeFieldName("propertyBundle");
412  catalog.writeStartArray();
413  catalog.writeStartObject();
414  catalog.writeStringField("@type", "PathRelation");
415  if (parent_path != null) {
416  catalog.writeStringField("path", parent_path + fileName);
417  } else {
418  catalog.writeStringField("path", fileName);
419  }
420  catalog.writeEndObject();
421  catalog.writeEndArray();
422 
423  catalog.writeEndObject();
424  }
425 }
static synchronized IngestManager getInstance()
static void generateReport(Long selectedDataSourceId, String reportOutputPath, ReportProgressPanel progressPanel)
void addReport(String localPath, String srcModuleName, String reportName)
Definition: Case.java:1690
static String saveDataSourceInfo(Long selectedDataSourceId, String caseTraceId, SleuthkitCase skCase, JsonGenerator jsonGenerator)
static String getStringTimeISO8601(long epochSeconds, TimeZone tzone)
static String saveCaseInfo(SleuthkitCase skCase, JsonGenerator catalog)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void saveFileInCaseUcoFormat(Long objectId, String fileName, String parent_path, String md5Hash, String mime_type, long size, String ctime, String atime, String mtime, String extension, JsonGenerator catalog, String dataSourceTraceId)
static String saveDataSourceInCaseUcoFormat(JsonGenerator catalog, String imageName, Long imageSize, Long selectedDataSourceId, String caseTraceId)

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