19 package org.sleuthkit.autopsy.report.modules.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;
66 private static final BlackboardAttribute.Type
SET_NAME =
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME);
67 private static final BlackboardArtifact.ARTIFACT_TYPE
INTERESTING_FILE_HIT = BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT;
68 private static final BlackboardArtifact.ARTIFACT_TYPE
INTERESTING_ARTIFACT_HIT = BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT;
82 "ReportCaseUco.unableToCreateDirectories=Unable to create directory for CASE-UCO report",
83 "ReportCaseUco.initializing=Creating directories...",
84 "ReportCaseUco.querying=Querying files...",
85 "ReportCaseUco.ingestWarning=Warning, this report will be created before ingest services completed",
86 "ReportCaseUco.datasourceMsg=Generating CASE-UCO Report for %s",
87 "ReportCaseUco.srcModuleName.text=CASE-UCO Report",
88 "ReportCaseUco.databaseError=Failed to get list of files from case database",
89 "ReportCaseUco.jsonError=Failed to create JSON output for the CASE-UCO report",
90 "ReportCaseUco.resultSetError=Unable to read result set",
91 "ReportCaseUco.noOpenCase=No current case open"
93 @SuppressWarnings(
"deprecation")
98 progressPanel.
start();
102 JsonFactory jsonGeneratorFactory =
new JsonFactory();
103 java.io.File reportFile = Paths.get(reportOutputPath).toFile();
105 Files.createDirectories(Paths.get(reportFile.getParent()));
106 }
catch (IOException ex) {
107 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 for (DataSource ds : skCase.getDataSources()) {
137 Bundle.ReportCaseUco_datasourceMsg(), ds.getName()));
140 long selectedDataSourceId = ds.getId();
141 String dataSourceTraceId =
saveDataSourceInfo(selectedDataSourceId, caseTraceId, skCase, jsonGenerator);
144 final String getAllFilesQuery =
"select obj_id, name, size, crtime, atime, mtime, md5, parent_path, mime_type, extension from tsk_files where "
145 +
"data_source_obj_id = " + Long.toString(selectedDataSourceId)
146 +
" AND ((meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_UNDEF.getValue()
147 +
") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
148 +
") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT.getValue() +
"))";
150 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getAllFilesQuery)) {
151 ResultSet resultSet = queryResult.getResultSet();
154 while (resultSet.next()) {
160 Long objectId = resultSet.getLong(1);
161 String fileName = resultSet.getString(2);
162 long size = resultSet.getLong(
"size");
166 String md5Hash = resultSet.getString(
"md5");
167 String parent_path = resultSet.getString(
"parent_path");
168 String mime_type = resultSet.getString(
"mime_type");
169 String extension = resultSet.getString(
"extension");
171 saveFileInCaseUcoFormat(objectId, fileName, parent_path, md5Hash, mime_type, size, crtime, atime, mtime, extension, jsonGenerator, dataSourceTraceId);
182 }
catch (TskCoreException ex) {
183 logger.log(Level.SEVERE, Bundle.ReportCaseUco_databaseError(), ex);
185 }
catch (IOException ex) {
186 logger.log(Level.SEVERE, Bundle.ReportCaseUco_jsonError(), ex);
188 }
catch (SQLException ex) {
189 logger.log(Level.WARNING, Bundle.ReportCaseUco_resultSetError(), ex);
192 logger.log(Level.SEVERE, Bundle.ReportCaseUco_noOpenCase(), ex);
195 if (jsonGenerator != null) {
197 jsonGenerator.close();
198 }
catch (IOException ex) {
199 logger.log(Level.WARNING,
"Failed to close JSON output file", ex);
220 "CaseUcoFormatExporter.startMsg=Generating CASE-UCO Report",
221 "CaseUcoFormatExporter.finishMsg=Finished generating CASE-UCO Report"
223 public static void export(List<TagName> tagTypes, List<String> interestingItemSets,
224 File caseReportFolder,
ReportProgressPanel progressPanel)
throws IOException, SQLException,
235 Path tmpDir = Paths.get(caseTempDirectory, TEMP_DIR_NAME);
236 FileUtils.deleteDirectory(tmpDir.toFile());
237 Files.createDirectory(tmpDir);
240 Path reportFile = Paths.get(caseReportFolder.toString(),
244 SimpleTimeZone timeZone =
new SimpleTimeZone(0,
"GMT");
249 String caseTraceId =
saveCaseInfo(skCase, jsonGenerator);
251 for (DataSource ds : skCase.getDataSources()) {
253 Bundle.ReportCaseUco_datasourceMsg(), ds.getName()));
255 caseTraceId, skCase, jsonGenerator);
256 for (TagName tn : tagTypes) {
259 jsonGenerator, timeZone, dataSourceTraceId);
263 jsonGenerator, timeZone, dataSourceTraceId);
266 if (!interestingItemSets.isEmpty()) {
267 List<BlackboardArtifact.ARTIFACT_TYPE> typesToQuery = Lists.newArrayList(
269 for (BlackboardArtifact.ARTIFACT_TYPE artType : typesToQuery) {
270 for (BlackboardArtifact bArt : skCase.getBlackboardArtifacts(artType)) {
271 if (bArt.getDataSource().getId() != ds.getId()) {
274 BlackboardAttribute setAttr = bArt.getAttribute(
SET_NAME);
275 if (interestingItemSets.contains(setAttr.getValueString())) {
276 Content content = skCase.getContentById(bArt.getObjectID());
278 jsonGenerator, timeZone, dataSourceTraceId);
302 TimeZone timeZone, String dataSourceTraceId)
throws IOException {
303 if (content instanceof AbstractFile && !(content instanceof DataSource)) {
304 AbstractFile absFile = (AbstractFile) content;
305 Path filePath = tmpDir.resolve(Long.toString(absFile.getId()));
306 if (!Files.exists(filePath) && !absFile.isDir()) {
310 absFile.getParentPath(),
311 absFile.getMd5Hash(),
312 absFile.getMIMEType(),
317 absFile.getNameExtension(),
321 filePath.toFile().createNewFile();
327 JsonFactory jsonGeneratorFactory =
new JsonFactory();
328 JsonGenerator jsonGenerator = jsonGeneratorFactory.createGenerator(reportFile, JsonEncoding.UTF8);
330 jsonGenerator.setPrettyPrinter(
new DefaultPrettyPrinter().withObjectIndenter(
new DefaultIndenter(
" ",
"\n")));
331 return jsonGenerator;
335 catalog.writeStartObject();
336 catalog.writeFieldName(
"@graph");
337 catalog.writeStartArray();
341 catalog.writeEndArray();
342 catalog.writeEndObject();
356 private static String
saveCaseInfo(SleuthkitCase skCase, JsonGenerator catalog)
throws TskCoreException, SQLException, IOException, NoCurrentCaseException {
359 String uniqueCaseName;
361 TskData.DbType dbType = skCase.getDatabaseType();
362 if (dbType == TskData.DbType.SQLITE) {
364 dbFileName = skCase.getDatabaseName();
366 uniqueCaseName = skCase.getDatabaseName();
370 String caseDirPath = skCase.getDbDirPath();
371 String caseTraceId =
"case-" + uniqueCaseName;
372 catalog.writeStartObject();
373 catalog.writeStringField(
"@id", caseTraceId);
374 catalog.writeStringField(
"@type",
"Trace");
376 catalog.writeFieldName(
"propertyBundle");
377 catalog.writeStartArray();
378 catalog.writeStartObject();
381 caseDirPath = caseDirPath.replaceAll(
"\\\\",
"/");
383 catalog.writeStringField(
"@type",
"File");
384 if (dbType == TskData.DbType.SQLITE) {
385 catalog.writeStringField(
"filePath", caseDirPath +
"/" + dbFileName);
386 catalog.writeBooleanField(
"isDirectory",
false);
388 catalog.writeStringField(
"filePath", caseDirPath);
389 catalog.writeBooleanField(
"isDirectory",
true);
391 catalog.writeEndObject();
393 catalog.writeEndArray();
394 catalog.writeEndObject();
411 private static String
saveDataSourceInfo(Long selectedDataSourceId, String caseTraceId, SleuthkitCase skCase, JsonGenerator jsonGenerator)
throws TskCoreException, SQLException, IOException {
413 Long imageSize = (long) 0;
414 String imageName =
"";
415 boolean isImageDataSource =
false;
416 String getImageDataSourceQuery =
"select size from tsk_image_info where obj_id = " + selectedDataSourceId;
417 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getImageDataSourceQuery)) {
418 ResultSet resultSet = queryResult.getResultSet();
420 while (resultSet.next()) {
422 imageSize = resultSet.getLong(1);
423 isImageDataSource =
true;
428 if (isImageDataSource) {
430 String getPathToDataSourceQuery =
"select name from tsk_image_names where obj_id = " + selectedDataSourceId;
431 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getPathToDataSourceQuery)) {
432 ResultSet resultSet = queryResult.getResultSet();
433 while (resultSet.next()) {
434 imageName = resultSet.getString(1);
440 String getLogicalDataSourceQuery =
"select name from tsk_files where obj_id = " + selectedDataSourceId;
441 try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getLogicalDataSourceQuery)) {
442 ResultSet resultSet = queryResult.getResultSet();
443 while (resultSet.next()) {
444 imageName = resultSet.getString(1);
453 private static String
saveDataSourceInCaseUcoFormat(JsonGenerator catalog, String imageName, Long imageSize, Long selectedDataSourceId, String caseTraceId)
throws IOException {
456 String dataSourceTraceId =
"data-source-" + selectedDataSourceId;
457 catalog.writeStartObject();
458 catalog.writeStringField(
"@id", dataSourceTraceId);
459 catalog.writeStringField(
"@type",
"Trace");
461 catalog.writeFieldName(
"propertyBundle");
462 catalog.writeStartArray();
464 catalog.writeStartObject();
465 catalog.writeStringField(
"@type",
"File");
468 imageName = imageName.replaceAll(
"\\\\",
"/");
470 catalog.writeStringField(
"filePath", imageName);
471 catalog.writeEndObject();
474 catalog.writeStartObject();
475 catalog.writeStringField(
"@type",
"ContentData");
476 catalog.writeStringField(
"sizeInBytes", Long.toString(imageSize));
477 catalog.writeEndObject();
480 catalog.writeEndArray();
481 catalog.writeEndObject();
484 catalog.writeStartObject();
485 catalog.writeStringField(
"@id",
"relationship-" + caseTraceId);
486 catalog.writeStringField(
"@type",
"Relationship");
487 catalog.writeStringField(
"source", dataSourceTraceId);
488 catalog.writeStringField(
"target", caseTraceId);
489 catalog.writeStringField(
"kindOfRelationship",
"contained-within");
490 catalog.writeBooleanField(
"isDirectional",
true);
492 catalog.writeFieldName(
"propertyBundle");
493 catalog.writeStartArray();
494 catalog.writeStartObject();
495 catalog.writeStringField(
"@type",
"PathRelation");
496 catalog.writeStringField(
"path", imageName);
497 catalog.writeEndObject();
498 catalog.writeEndArray();
500 catalog.writeEndObject();
502 return dataSourceTraceId;
505 private static void saveFileInCaseUcoFormat(Long objectId, String fileName, String parent_path, String md5Hash, String mime_type,
long size, String ctime,
506 String atime, String mtime, String extension, JsonGenerator catalog, String dataSourceTraceId)
throws IOException {
508 String fileTraceId =
"file-" + objectId;
511 catalog.writeStartObject();
512 catalog.writeStringField(
"@id", fileTraceId);
513 catalog.writeStringField(
"@type",
"Trace");
515 catalog.writeFieldName(
"propertyBundle");
516 catalog.writeStartArray();
518 catalog.writeStartObject();
519 catalog.writeStringField(
"@type",
"File");
520 catalog.writeStringField(
"createdTime", ctime);
521 catalog.writeStringField(
"accessedTime", atime);
522 catalog.writeStringField(
"modifiedTime", mtime);
523 if (extension != null) {
524 catalog.writeStringField(
"extension", extension);
526 catalog.writeStringField(
"fileName", fileName);
527 if (parent_path != null) {
528 catalog.writeStringField(
"filePath", parent_path + fileName);
530 catalog.writeBooleanField(
"isDirectory",
false);
531 catalog.writeStringField(
"sizeInBytes", Long.toString(size));
532 catalog.writeEndObject();
534 catalog.writeStartObject();
535 catalog.writeStringField(
"@type",
"ContentData");
536 if (mime_type != null) {
537 catalog.writeStringField(
"mimeType", mime_type);
539 if (md5Hash != null) {
540 catalog.writeFieldName(
"hash");
541 catalog.writeStartArray();
542 catalog.writeStartObject();
543 catalog.writeStringField(
"@type",
"Hash");
544 catalog.writeStringField(
"hashMethod",
"MD5");
545 catalog.writeStringField(
"hashValue", md5Hash);
546 catalog.writeEndObject();
547 catalog.writeEndArray();
549 catalog.writeStringField(
"sizeInBytes", Long.toString(size));
551 catalog.writeEndObject();
553 catalog.writeEndArray();
554 catalog.writeEndObject();
557 catalog.writeStartObject();
558 catalog.writeStringField(
"@id",
"relationship-" + objectId);
559 catalog.writeStringField(
"@type",
"Relationship");
560 catalog.writeStringField(
"source", fileTraceId);
561 catalog.writeStringField(
"target", dataSourceTraceId);
562 catalog.writeStringField(
"kindOfRelationship",
"contained-within");
563 catalog.writeBooleanField(
"isDirectional",
true);
565 catalog.writeFieldName(
"propertyBundle");
566 catalog.writeStartArray();
567 catalog.writeStartObject();
568 catalog.writeStringField(
"@type",
"PathRelation");
569 if (parent_path != null) {
570 catalog.writeStringField(
"path", parent_path + fileName);
572 catalog.writeStringField(
"path", fileName);
574 catalog.writeEndObject();
575 catalog.writeEndArray();
577 catalog.writeEndObject();
static synchronized IngestManager getInstance()
String getTempDirectory()
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()
static String getReportFileName()
SleuthkitCase getSleuthkitCase()
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
void updateStatusLabel(String statusMessage)