20 package org.sleuthkit.autopsy.modules.case_uco;
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.nio.file.Paths;
25 import java.util.logging.Level;
26 import javax.swing.JPanel;
27 import com.fasterxml.jackson.core.JsonEncoding;
28 import com.fasterxml.jackson.core.JsonFactory;
29 import com.fasterxml.jackson.core.JsonGenerator;
30 import com.fasterxml.jackson.core.util.DefaultIndenter;
31 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
32 import java.sql.ResultSet;
33 import java.sql.SQLException;
34 import java.util.SimpleTimeZone;
35 import org.openide.util.NbBundle;
54 private static ReportCaseUco instance = null;
55 private ReportCaseUcoConfigPanel configPanel;
57 private static final String REPORT_FILE_NAME =
"CASE_UCO_output.json-ld";
60 private ReportCaseUco() {
64 public static synchronized ReportCaseUco getDefault() {
65 if (instance == null) {
66 instance =
new ReportCaseUco();
78 "ReportCaseUco.notInitialized=CASE-UCO settings panel has not been initialized",
79 "ReportCaseUco.noDataSourceSelected=No data source selected for CASE-UCO report",
80 "ReportCaseUco.noCaseOpen=Unable to open currect case",
81 "ReportCaseUco.unableToCreateDirectories=Unable to create directory for CASE-UCO report",
82 "ReportCaseUco.initializing=Creating directories...",
83 "ReportCaseUco.querying=Querying files...",
84 "ReportCaseUco.ingestWarning=Warning, this report will be created before ingest services completed",
85 "ReportCaseUco.processing=Saving files in CASE-UCO format...",
86 "ReportCaseUco.srcModuleName.text=CASE-UCO Report"
89 @SuppressWarnings(
"deprecation")
92 if (configPanel == null) {
93 logger.log(Level.SEVERE,
"CASE-UCO settings panel has not been initialized");
99 Long selectedDataSourceId = configPanel.getSelectedDataSourceId();
100 if (selectedDataSourceId == ReportCaseUcoConfigPanel.NO_DATA_SOURCE_SELECTED) {
101 logger.log(Level.SEVERE,
"No data source selected for CASE-UCO report");
109 progressPanel.
start();
113 JsonFactory jsonGeneratorFactory =
new JsonFactory();
114 String reportPath = baseReportDir + getRelativeFilePath();
115 java.io.File reportFile = Paths.get(reportPath).toFile();
117 Files.createDirectories(Paths.get(reportFile.getParent()));
118 }
catch (IOException ex) {
119 logger.log(Level.SEVERE,
"Unable to create directory for CASE-UCO report", ex);
131 JsonGenerator jsonGenerator = null;
132 SimpleTimeZone timeZone =
new SimpleTimeZone(0,
"GMT");
134 jsonGenerator = jsonGeneratorFactory.createGenerator(reportFile, JsonEncoding.UTF8);
136 jsonGenerator.setPrettyPrinter(
new DefaultPrettyPrinter().withObjectIndenter(
new DefaultIndenter(
" ",
"\n")));
143 initializeJsonOutputFile(jsonGenerator);
146 String caseTraceId = saveCaseInfo(skCase, jsonGenerator);
149 String dataSourceTraceId = saveDataSourceInfo(selectedDataSourceId, caseTraceId, skCase, jsonGenerator);
152 final String getAllFilesQuery =
"select obj_id, name, size, crtime, atime, mtime, md5, parent_path, mime_type, extension from tsk_files where "
153 +
"data_source_obj_id = " + Long.toString(selectedDataSourceId)
154 +
" AND ((meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_UNDEF.getValue()
155 +
") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
156 +
") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT.getValue() +
"))";
158 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getAllFilesQuery)) {
159 ResultSet resultSet = queryResult.getResultSet();
164 while (resultSet.next()) {
170 Long objectId = resultSet.getLong(1);
171 String fileName = resultSet.getString(2);
172 long size = resultSet.getLong(
"size");
176 String md5Hash = resultSet.getString(
"md5");
177 String parent_path = resultSet.getString(
"parent_path");
178 String mime_type = resultSet.getString(
"mime_type");
179 String extension = resultSet.getString(
"extension");
181 saveFileInCaseUcoFormat(objectId, fileName, parent_path, md5Hash, mime_type, size, crtime, atime, mtime, extension, jsonGenerator, dataSourceTraceId);
186 finilizeJsonOutputFile(jsonGenerator);
191 }
catch (TskCoreException ex) {
192 logger.log(Level.SEVERE,
"Failed to get list of files from case database", ex);
194 }
catch (IOException ex) {
195 logger.log(Level.SEVERE,
"Failed to create JSON output for the CASE-UCO report", ex);
197 }
catch (SQLException ex) {
198 logger.log(Level.WARNING,
"Unable to read result set", ex);
201 logger.log(Level.SEVERE,
"No current case open", ex);
204 if (jsonGenerator != null) {
206 jsonGenerator.close();
207 }
catch (IOException ex) {
208 logger.log(Level.WARNING,
"Failed to close JSON output file", ex);
214 private void initializeJsonOutputFile(JsonGenerator catalog)
throws IOException {
215 catalog.writeStartObject();
216 catalog.writeFieldName(
"@graph");
217 catalog.writeStartArray();
220 private void finilizeJsonOutputFile(JsonGenerator catalog)
throws IOException {
221 catalog.writeEndArray();
222 catalog.writeEndObject();
225 private String saveCaseInfo(SleuthkitCase skCase, JsonGenerator catalog)
throws TskCoreException, SQLException, IOException,
NoCurrentCaseException {
228 String uniqueCaseName;
230 TskData.DbType dbType = skCase.getDatabaseType();
231 if (dbType == TskData.DbType.SQLITE) {
233 dbFileName = skCase.getDatabaseName();
235 uniqueCaseName = skCase.getDatabaseName();
239 String caseDirPath = skCase.getDbDirPath();
240 String caseTraceId =
"case-" + uniqueCaseName;
241 catalog.writeStartObject();
242 catalog.writeStringField(
"@id", caseTraceId);
243 catalog.writeStringField(
"@type",
"Trace");
245 catalog.writeFieldName(
"propertyBundle");
246 catalog.writeStartArray();
247 catalog.writeStartObject();
250 caseDirPath = caseDirPath.replaceAll(
"\\\\",
"/");
252 catalog.writeStringField(
"@type",
"File");
253 if (dbType == TskData.DbType.SQLITE) {
254 catalog.writeStringField(
"filePath", caseDirPath +
"/" + dbFileName);
255 catalog.writeBooleanField(
"isDirectory",
false);
257 catalog.writeStringField(
"filePath", caseDirPath);
258 catalog.writeBooleanField(
"isDirectory",
true);
260 catalog.writeEndObject();
262 catalog.writeEndArray();
263 catalog.writeEndObject();
268 private String saveDataSourceInfo(Long selectedDataSourceId, String caseTraceId, SleuthkitCase skCase, JsonGenerator jsonGenerator)
throws TskCoreException, SQLException, IOException {
270 Long imageSize = (long) 0;
271 String imageName =
"";
272 boolean isImageDataSource =
false;
273 String getImageDataSourceQuery =
"select size from tsk_image_info where obj_id = " + selectedDataSourceId;
274 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getImageDataSourceQuery)) {
275 ResultSet resultSet = queryResult.getResultSet();
277 while (resultSet.next()) {
279 imageSize = resultSet.getLong(1);
280 isImageDataSource =
true;
285 if (isImageDataSource) {
287 String getPathToDataSourceQuery =
"select name from tsk_image_names where obj_id = " + selectedDataSourceId;
288 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getPathToDataSourceQuery)) {
289 ResultSet resultSet = queryResult.getResultSet();
290 while (resultSet.next()) {
291 imageName = resultSet.getString(1);
297 String getLogicalDataSourceQuery =
"select name from tsk_files where obj_id = " + selectedDataSourceId;
298 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getLogicalDataSourceQuery)) {
299 ResultSet resultSet = queryResult.getResultSet();
300 while (resultSet.next()) {
301 imageName = resultSet.getString(1);
307 return saveDataSourceInCaseUcoFormat(jsonGenerator, imageName, imageSize, selectedDataSourceId, caseTraceId);
310 private String saveDataSourceInCaseUcoFormat(JsonGenerator catalog, String imageName, Long imageSize, Long selectedDataSourceId, String caseTraceId)
throws IOException {
313 String dataSourceTraceId =
"data-source-"+selectedDataSourceId;
314 catalog.writeStartObject();
315 catalog.writeStringField(
"@id", dataSourceTraceId);
316 catalog.writeStringField(
"@type",
"Trace");
318 catalog.writeFieldName(
"propertyBundle");
319 catalog.writeStartArray();
321 catalog.writeStartObject();
322 catalog.writeStringField(
"@type",
"File");
325 imageName = imageName.replaceAll(
"\\\\",
"/");
327 catalog.writeStringField(
"filePath", imageName);
328 catalog.writeEndObject();
331 catalog.writeStartObject();
332 catalog.writeStringField(
"@type",
"ContentData");
333 catalog.writeStringField(
"sizeInBytes", Long.toString(imageSize));
334 catalog.writeEndObject();
337 catalog.writeEndArray();
338 catalog.writeEndObject();
341 catalog.writeStartObject();
342 catalog.writeStringField(
"@id",
"relationship-" + caseTraceId);
343 catalog.writeStringField(
"@type",
"Relationship");
344 catalog.writeStringField(
"source", dataSourceTraceId);
345 catalog.writeStringField(
"target", caseTraceId);
346 catalog.writeStringField(
"kindOfRelationship",
"contained-within");
347 catalog.writeBooleanField(
"isDirectional",
true);
349 catalog.writeFieldName(
"propertyBundle");
350 catalog.writeStartArray();
351 catalog.writeStartObject();
352 catalog.writeStringField(
"@type",
"PathRelation");
353 catalog.writeStringField(
"path", imageName);
354 catalog.writeEndObject();
355 catalog.writeEndArray();
357 catalog.writeEndObject();
359 return dataSourceTraceId;
362 private void saveFileInCaseUcoFormat(Long objectId, String fileName, String parent_path, String md5Hash, String mime_type,
long size, String ctime,
363 String atime, String mtime, String extension, JsonGenerator catalog, String dataSourceTraceId)
throws IOException {
365 String fileTraceId =
"file-" + objectId;
368 catalog.writeStartObject();
369 catalog.writeStringField(
"@id", fileTraceId);
370 catalog.writeStringField(
"@type",
"Trace");
372 catalog.writeFieldName(
"propertyBundle");
373 catalog.writeStartArray();
375 catalog.writeStartObject();
376 catalog.writeStringField(
"@type",
"File");
377 catalog.writeStringField(
"createdTime", ctime);
378 catalog.writeStringField(
"accessedTime", atime);
379 catalog.writeStringField(
"modifiedTime", mtime);
380 if (extension != null) {
381 catalog.writeStringField(
"extension", extension);
383 catalog.writeStringField(
"fileName", fileName);
384 if (parent_path != null) {
385 catalog.writeStringField(
"filePath", parent_path + fileName);
387 catalog.writeBooleanField(
"isDirectory",
false);
388 catalog.writeStringField(
"sizeInBytes", Long.toString(size));
389 catalog.writeEndObject();
391 catalog.writeStartObject();
392 catalog.writeStringField(
"@type",
"ContentData");
393 if (mime_type != null) {
394 catalog.writeStringField(
"mimeType", mime_type);
396 if (md5Hash != null) {
397 catalog.writeFieldName(
"hash");
398 catalog.writeStartArray();
399 catalog.writeStartObject();
400 catalog.writeStringField(
"@type",
"Hash");
401 catalog.writeStringField(
"hashMethod",
"MD5");
402 catalog.writeStringField(
"hashValue", md5Hash);
403 catalog.writeEndObject();
404 catalog.writeEndArray();
406 catalog.writeStringField(
"sizeInBytes", Long.toString(size));
408 catalog.writeEndObject();
410 catalog.writeEndArray();
411 catalog.writeEndObject();
414 catalog.writeStartObject();
415 catalog.writeStringField(
"@id",
"relationship-" + objectId);
416 catalog.writeStringField(
"@type",
"Relationship");
417 catalog.writeStringField(
"source", fileTraceId);
418 catalog.writeStringField(
"target", dataSourceTraceId);
419 catalog.writeStringField(
"kindOfRelationship",
"contained-within");
420 catalog.writeBooleanField(
"isDirectional",
true);
422 catalog.writeFieldName(
"propertyBundle");
423 catalog.writeStartArray();
424 catalog.writeStartObject();
425 catalog.writeStringField(
"@type",
"PathRelation");
426 if (parent_path != null) {
427 catalog.writeStringField(
"path", parent_path + fileName);
429 catalog.writeStringField(
"path", fileName);
431 catalog.writeEndObject();
432 catalog.writeEndArray();
434 catalog.writeEndObject();
438 public String getName() {
439 String name = NbBundle.getMessage(this.getClass(),
"ReportCaseUco.getName.text");
444 public String getRelativeFilePath() {
445 return REPORT_FILE_NAME;
449 public String getDescription() {
450 String desc = NbBundle.getMessage(this.getClass(),
"ReportCaseUco.getDesc.text");
455 public JPanel getConfigurationPanel() {
457 configPanel =
new ReportCaseUcoConfigPanel();
459 logger.log(Level.SEVERE,
"Failed to initialize CASE-UCO settings panel", ex);
static synchronized IngestManager getInstance()
static void warn(String message)
void complete(ReportStatus reportStatus)
boolean isIngestRunning()
void addReport(String localPath, String srcModuleName, String reportName)
void setIndeterminate(boolean indeterminate)
static String getStringTimeISO8601(long epochSeconds, TimeZone tzone)
SleuthkitCase getSleuthkitCase()
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
void updateStatusLabel(String statusMessage)
static void error(String message)