19 package org.sleuthkit.autopsy.report.caseuco;
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 com.google.common.collect.Lists;
28 import java.io.IOException;
29 import java.nio.file.Files;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.sql.ResultSet;
33 import java.sql.SQLException;
34 import java.util.List;
35 import java.util.SimpleTimeZone;
36 import java.util.TimeZone;
37 import java.util.logging.Level;
38 import org.apache.commons.io.FileUtils;
39 import org.openide.util.NbBundle;
67 private static final BlackboardAttribute.Type
SET_NAME =
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME);
68 private static final BlackboardArtifact.ARTIFACT_TYPE
INTERESTING_FILE_HIT = BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT;
69 private static final BlackboardArtifact.ARTIFACT_TYPE
INTERESTING_ARTIFACT_HIT = BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT;
84 "ReportCaseUco.noCaseOpen=Unable to open currect case",
85 "ReportCaseUco.unableToCreateDirectories=Unable to create directory for CASE-UCO report",
86 "ReportCaseUco.initializing=Creating directories...",
87 "ReportCaseUco.querying=Querying files...",
88 "ReportCaseUco.ingestWarning=Warning, this report will be created before ingest services completed",
89 "ReportCaseUco.processing=Saving files in CASE-UCO format...",
90 "ReportCaseUco.srcModuleName.text=CASE-UCO Report"
92 @SuppressWarnings(
"deprecation")
97 progressPanel.
start();
101 JsonFactory jsonGeneratorFactory =
new JsonFactory();
102 java.io.File reportFile = Paths.get(reportOutputPath).toFile();
104 Files.createDirectories(Paths.get(reportFile.getParent()));
105 }
catch (IOException ex) {
106 logger.log(Level.SEVERE,
"Unable to create directory for CASE-UCO report", ex);
117 JsonGenerator jsonGenerator = null;
118 SimpleTimeZone timeZone =
new SimpleTimeZone(0,
"GMT");
120 jsonGenerator = jsonGeneratorFactory.createGenerator(reportFile, JsonEncoding.UTF8);
122 jsonGenerator.setPrettyPrinter(
new DefaultPrettyPrinter().withObjectIndenter(
new DefaultIndenter(
" ",
"\n")));
132 String caseTraceId =
saveCaseInfo(skCase, jsonGenerator);
135 String dataSourceTraceId =
saveDataSourceInfo(selectedDataSourceId, caseTraceId, skCase, jsonGenerator);
138 final String getAllFilesQuery =
"select obj_id, name, size, crtime, atime, mtime, md5, parent_path, mime_type, extension from tsk_files where "
139 +
"data_source_obj_id = " + Long.toString(selectedDataSourceId)
140 +
" AND ((meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_UNDEF.getValue()
141 +
") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
142 +
") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT.getValue() +
"))";
144 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getAllFilesQuery)) {
145 ResultSet resultSet = queryResult.getResultSet();
150 while (resultSet.next()) {
156 Long objectId = resultSet.getLong(1);
157 String fileName = resultSet.getString(2);
158 long size = resultSet.getLong(
"size");
162 String md5Hash = resultSet.getString(
"md5");
163 String parent_path = resultSet.getString(
"parent_path");
164 String mime_type = resultSet.getString(
"mime_type");
165 String extension = resultSet.getString(
"extension");
167 saveFileInCaseUcoFormat(objectId, fileName, parent_path, md5Hash, mime_type, size, crtime, atime, mtime, extension, jsonGenerator, dataSourceTraceId);
177 }
catch (TskCoreException ex) {
178 logger.log(Level.SEVERE,
"Failed to get list of files from case database", ex);
180 }
catch (IOException ex) {
181 logger.log(Level.SEVERE,
"Failed to create JSON output for the CASE-UCO report", ex);
183 }
catch (SQLException ex) {
184 logger.log(Level.WARNING,
"Unable to read result set", ex);
187 logger.log(Level.SEVERE,
"No current case open", ex);
190 if (jsonGenerator != null) {
192 jsonGenerator.close();
193 }
catch (IOException ex) {
194 logger.log(Level.WARNING,
"Failed to close JSON output file", ex);
215 "CaseUcoFormatExporter.startMsg=Generating CASE-UCO Report",
216 "CaseUcoFormatExporter.datasourceMsg=Generating CASE-UCO Report for %s",
217 "CaseUcoFormatExporter.finishMsg=Finished generating CASE-UCO Report"
219 public static void export(List<TagName> tagTypes, List<String> interestingItemSets,
220 File caseReportFolder,
ReportProgressPanel progressPanel)
throws IOException, SQLException,
231 Path tmpDir = Paths.get(caseTempDirectory, TEMP_DIR_NAME);
232 FileUtils.deleteDirectory(tmpDir.toFile());
233 Files.createDirectory(tmpDir);
236 Path reportFile = Paths.get(caseReportFolder.toString(),
240 SimpleTimeZone timeZone =
new SimpleTimeZone(0,
"GMT");
245 String caseTraceId =
saveCaseInfo(skCase, jsonGenerator);
247 for (DataSource ds : skCase.getDataSources()) {
249 Bundle.CaseUcoFormatExporter_datasourceMsg(), ds.getName()));
251 caseTraceId, skCase, jsonGenerator);
252 for (TagName tn : tagTypes) {
255 jsonGenerator, timeZone, dataSourceTraceId);
259 jsonGenerator, timeZone, dataSourceTraceId);
262 if(!interestingItemSets.isEmpty()) {
263 List<BlackboardArtifact.ARTIFACT_TYPE> typesToQuery = Lists.newArrayList(
265 for(BlackboardArtifact.ARTIFACT_TYPE artType : typesToQuery) {
266 for(BlackboardArtifact bArt : skCase.getBlackboardArtifacts(artType)) {
267 if(bArt.getDataSource().getId() != ds.getId()) {
270 BlackboardAttribute setAttr = bArt.getAttribute(
SET_NAME);
271 if (interestingItemSets.contains(setAttr.getValueString())) {
272 Content content = skCase.getContentById(bArt.getObjectID());
274 jsonGenerator, timeZone, dataSourceTraceId);
298 TimeZone timeZone, String dataSourceTraceId)
throws IOException {
299 if (content instanceof AbstractFile && !(content instanceof DataSource)) {
300 AbstractFile absFile = (AbstractFile) content;
301 Path filePath = tmpDir.resolve(Long.toString(absFile.getId()));
302 if (!Files.exists(filePath) && !absFile.isDir()) {
306 absFile.getParentPath(),
307 absFile.getMd5Hash(),
308 absFile.getMIMEType(),
313 absFile.getNameExtension(),
317 filePath.toFile().createNewFile();
323 JsonFactory jsonGeneratorFactory =
new JsonFactory();
324 JsonGenerator jsonGenerator = jsonGeneratorFactory.createGenerator(reportFile, JsonEncoding.UTF8);
326 jsonGenerator.setPrettyPrinter(
new DefaultPrettyPrinter().withObjectIndenter(
new DefaultIndenter(
" ",
"\n")));
327 return jsonGenerator;
331 catalog.writeStartObject();
332 catalog.writeFieldName(
"@graph");
333 catalog.writeStartArray();
337 catalog.writeEndArray();
338 catalog.writeEndObject();
352 private static String
saveCaseInfo(SleuthkitCase skCase, JsonGenerator catalog)
throws TskCoreException, SQLException, IOException, NoCurrentCaseException {
355 String uniqueCaseName;
357 TskData.DbType dbType = skCase.getDatabaseType();
358 if (dbType == TskData.DbType.SQLITE) {
360 dbFileName = skCase.getDatabaseName();
362 uniqueCaseName = skCase.getDatabaseName();
366 String caseDirPath = skCase.getDbDirPath();
367 String caseTraceId =
"case-" + uniqueCaseName;
368 catalog.writeStartObject();
369 catalog.writeStringField(
"@id", caseTraceId);
370 catalog.writeStringField(
"@type",
"Trace");
372 catalog.writeFieldName(
"propertyBundle");
373 catalog.writeStartArray();
374 catalog.writeStartObject();
377 caseDirPath = caseDirPath.replaceAll(
"\\\\",
"/");
379 catalog.writeStringField(
"@type",
"File");
380 if (dbType == TskData.DbType.SQLITE) {
381 catalog.writeStringField(
"filePath", caseDirPath +
"/" + dbFileName);
382 catalog.writeBooleanField(
"isDirectory",
false);
384 catalog.writeStringField(
"filePath", caseDirPath);
385 catalog.writeBooleanField(
"isDirectory",
true);
387 catalog.writeEndObject();
389 catalog.writeEndArray();
390 catalog.writeEndObject();
407 private static String
saveDataSourceInfo(Long selectedDataSourceId, String caseTraceId, SleuthkitCase skCase, JsonGenerator jsonGenerator)
throws TskCoreException, SQLException, IOException {
409 Long imageSize = (long) 0;
410 String imageName =
"";
411 boolean isImageDataSource =
false;
412 String getImageDataSourceQuery =
"select size from tsk_image_info where obj_id = " + selectedDataSourceId;
413 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getImageDataSourceQuery)) {
414 ResultSet resultSet = queryResult.getResultSet();
416 while (resultSet.next()) {
418 imageSize = resultSet.getLong(1);
419 isImageDataSource =
true;
424 if (isImageDataSource) {
426 String getPathToDataSourceQuery =
"select name from tsk_image_names where obj_id = " + selectedDataSourceId;
427 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getPathToDataSourceQuery)) {
428 ResultSet resultSet = queryResult.getResultSet();
429 while (resultSet.next()) {
430 imageName = resultSet.getString(1);
436 String getLogicalDataSourceQuery =
"select name from tsk_files where obj_id = " + selectedDataSourceId;
437 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getLogicalDataSourceQuery)) {
438 ResultSet resultSet = queryResult.getResultSet();
439 while (resultSet.next()) {
440 imageName = resultSet.getString(1);
449 private static String
saveDataSourceInCaseUcoFormat(JsonGenerator catalog, String imageName, Long imageSize, Long selectedDataSourceId, String caseTraceId)
throws IOException {
452 String dataSourceTraceId =
"data-source-" + selectedDataSourceId;
453 catalog.writeStartObject();
454 catalog.writeStringField(
"@id", dataSourceTraceId);
455 catalog.writeStringField(
"@type",
"Trace");
457 catalog.writeFieldName(
"propertyBundle");
458 catalog.writeStartArray();
460 catalog.writeStartObject();
461 catalog.writeStringField(
"@type",
"File");
464 imageName = imageName.replaceAll(
"\\\\",
"/");
466 catalog.writeStringField(
"filePath", imageName);
467 catalog.writeEndObject();
470 catalog.writeStartObject();
471 catalog.writeStringField(
"@type",
"ContentData");
472 catalog.writeStringField(
"sizeInBytes", Long.toString(imageSize));
473 catalog.writeEndObject();
476 catalog.writeEndArray();
477 catalog.writeEndObject();
480 catalog.writeStartObject();
481 catalog.writeStringField(
"@id",
"relationship-" + caseTraceId);
482 catalog.writeStringField(
"@type",
"Relationship");
483 catalog.writeStringField(
"source", dataSourceTraceId);
484 catalog.writeStringField(
"target", caseTraceId);
485 catalog.writeStringField(
"kindOfRelationship",
"contained-within");
486 catalog.writeBooleanField(
"isDirectional",
true);
488 catalog.writeFieldName(
"propertyBundle");
489 catalog.writeStartArray();
490 catalog.writeStartObject();
491 catalog.writeStringField(
"@type",
"PathRelation");
492 catalog.writeStringField(
"path", imageName);
493 catalog.writeEndObject();
494 catalog.writeEndArray();
496 catalog.writeEndObject();
498 return dataSourceTraceId;
501 private static void saveFileInCaseUcoFormat(Long objectId, String fileName, String parent_path, String md5Hash, String mime_type,
long size, String ctime,
502 String atime, String mtime, String extension, JsonGenerator catalog, String dataSourceTraceId)
throws IOException {
504 String fileTraceId =
"file-" + objectId;
507 catalog.writeStartObject();
508 catalog.writeStringField(
"@id", fileTraceId);
509 catalog.writeStringField(
"@type",
"Trace");
511 catalog.writeFieldName(
"propertyBundle");
512 catalog.writeStartArray();
514 catalog.writeStartObject();
515 catalog.writeStringField(
"@type",
"File");
516 catalog.writeStringField(
"createdTime", ctime);
517 catalog.writeStringField(
"accessedTime", atime);
518 catalog.writeStringField(
"modifiedTime", mtime);
519 if (extension != null) {
520 catalog.writeStringField(
"extension", extension);
522 catalog.writeStringField(
"fileName", fileName);
523 if (parent_path != null) {
524 catalog.writeStringField(
"filePath", parent_path + fileName);
526 catalog.writeBooleanField(
"isDirectory",
false);
527 catalog.writeStringField(
"sizeInBytes", Long.toString(size));
528 catalog.writeEndObject();
530 catalog.writeStartObject();
531 catalog.writeStringField(
"@type",
"ContentData");
532 if (mime_type != null) {
533 catalog.writeStringField(
"mimeType", mime_type);
535 if (md5Hash != null) {
536 catalog.writeFieldName(
"hash");
537 catalog.writeStartArray();
538 catalog.writeStartObject();
539 catalog.writeStringField(
"@type",
"Hash");
540 catalog.writeStringField(
"hashMethod",
"MD5");
541 catalog.writeStringField(
"hashValue", md5Hash);
542 catalog.writeEndObject();
543 catalog.writeEndArray();
545 catalog.writeStringField(
"sizeInBytes", Long.toString(size));
547 catalog.writeEndObject();
549 catalog.writeEndArray();
550 catalog.writeEndObject();
553 catalog.writeStartObject();
554 catalog.writeStringField(
"@id",
"relationship-" + objectId);
555 catalog.writeStringField(
"@type",
"Relationship");
556 catalog.writeStringField(
"source", fileTraceId);
557 catalog.writeStringField(
"target", dataSourceTraceId);
558 catalog.writeStringField(
"kindOfRelationship",
"contained-within");
559 catalog.writeBooleanField(
"isDirectional",
true);
561 catalog.writeFieldName(
"propertyBundle");
562 catalog.writeStartArray();
563 catalog.writeStartObject();
564 catalog.writeStringField(
"@type",
"PathRelation");
565 if (parent_path != null) {
566 catalog.writeStringField(
"path", parent_path + fileName);
568 catalog.writeStringField(
"path", fileName);
570 catalog.writeEndObject();
571 catalog.writeEndArray();
573 catalog.writeEndObject();
static synchronized IngestManager getInstance()
String getTempDirectory()
static void warn(String message)
static String getReportFileName()
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)
TagsManager getTagsManager()
SleuthkitCase getSleuthkitCase()
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
void updateStatusLabel(String statusMessage)
static void error(String message)