19 package org.sleuthkit.autopsy.report.modules.portablecase;
21 import com.google.common.collect.ArrayListMultimap;
22 import com.google.common.collect.Multimap;
23 import com.google.gson.Gson;
24 import com.google.gson.GsonBuilder;
25 import com.google.gson.JsonElement;
26 import com.google.gson.stream.JsonWriter;
28 import java.util.logging.Level;
29 import java.io.BufferedReader;
31 import java.io.FileOutputStream;
32 import java.io.FileWriter;
33 import java.io.InputStreamReader;
34 import java.io.IOException;
35 import java.io.OutputStream;
36 import java.io.OutputStreamWriter;
37 import java.nio.file.Files;
38 import java.nio.file.Path;
39 import java.nio.file.Paths;
40 import java.sql.ResultSet;
41 import java.sql.SQLException;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.Collection;
45 import java.util.HashMap;
46 import java.util.List;
48 import org.apache.commons.io.FileUtils;
49 import org.openide.modules.InstalledFileLocator;
50 import org.openide.util.NbBundle;
65 import org.
sleuthkit.datamodel.Blackboard.BlackboardException;
78 import org.
sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
80 import org.
sleuthkit.datamodel.TaggingManager.ContentTagChange;
85 import org.
sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper;
86 import org.
sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
87 import org.
sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments;
108 private static final List<Integer>
SPECIALLY_HANDLED_ATTRS = Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID(),
109 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID());
139 "PortableCaseReportModule.getName.name=Portable Case"
143 return Bundle.PortableCaseReportModule_getName_name();
147 "PortableCaseReportModule.getDescription.description=Copies selected items to a new single-user case that can be easily shared"
151 return Bundle.PortableCaseReportModule_getDescription_description();
171 logger.log(Level.INFO,
"Portable case creation canceled by user");
189 logger.log(Level.WARNING, logWarning);
191 logger.log(Level.SEVERE, logWarning, ex);
199 "PortableCaseReportModule.generateReport.verifying=Verifying selected parameters...",
200 "PortableCaseReportModule.generateReport.creatingCase=Creating portable case database...",
201 "PortableCaseReportModule.generateReport.copyingTags=Copying tags...",
203 "PortableCaseReportModule.generateReport.copyingFiles=Copying files tagged as {0}...",
205 "PortableCaseReportModule.generateReport.copyingArtifacts=Copying artifacts tagged as {0}...",
206 "# {0} - output folder",
207 "PortableCaseReportModule.generateReport.outputDirDoesNotExist=Output folder {0} does not exist",
208 "# {0} - output folder",
209 "PortableCaseReportModule.generateReport.outputDirIsNotDir=Output folder {0} is not a folder",
210 "PortableCaseReportModule.generateReport.caseClosed=Current case has been closed",
211 "PortableCaseReportModule.generateReport.interestingItemError=Error loading intersting items",
212 "PortableCaseReportModule.generateReport.errorReadingTags=Error while reading tags from case database",
213 "PortableCaseReportModule.generateReport.errorReadingSets=Error while reading interesting items sets from case database",
214 "PortableCaseReportModule.generateReport.noContentToCopy=No interesting files, results, or tagged items to copy",
215 "PortableCaseReportModule.generateReport.errorCopyingTags=Error copying tags",
216 "PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged files",
217 "PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
218 "PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files",
219 "PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results",
220 "PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table",
221 "PortableCaseReportModule.generateReport.errorCopyingAutopsy=Error copying application",
222 "# {0} - attribute type name",
223 "PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
224 "PortableCaseReportModule.generateReport.compressingCase=Compressing case...",
225 "PortableCaseReportModule_generateReport_copyingAutopsy=Copying application..."
229 this.settings = options;
231 progressPanel.
start();
232 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_verifying());
238 File outputDir =
new File(reportPath);
239 if (!outputDir.exists()) {
240 handleError(
"Output folder " + outputDir.toString() +
" does not exist",
241 Bundle.PortableCaseReportModule_generateReport_outputDirDoesNotExist(outputDir.toString()), null, progressPanel);
245 if (!outputDir.isDirectory()) {
246 handleError(
"Output folder " + outputDir.toString() +
" is not a folder",
247 Bundle.PortableCaseReportModule_generateReport_outputDirIsNotDir(outputDir.toString()), null, progressPanel);
257 Bundle.PortableCaseReportModule_generateReport_caseClosed(), null, progressPanel);
263 outputDir = Paths.get(outputDir.toString(),
caseName).toFile();
266 List<TagName> tagNames;
272 Bundle.PortableCaseReportModule_generateReport_errorReadingTags(), ex, progressPanel);
279 List<String> setNames;
284 handleError(
"Unable to get all interesting items sets",
285 Bundle.PortableCaseReportModule_generateReport_errorReadingSets(), ex, progressPanel);
292 if (tagNames.isEmpty() && setNames.isEmpty()) {
294 Bundle.PortableCaseReportModule_generateReport_noContentToCopy(), null, progressPanel);
300 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_creatingCase());
302 if (portableSkCase == null) {
316 }
catch (TskCoreException ex) {
317 handleError(
"Error creating image tag table", Bundle.PortableCaseReportModule_generateReport_errorCreatingImageTagTable(), ex, progressPanel);
322 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags());
324 for (TagName tagName : tagNames) {
325 TagName newTagName = portableSkCase.addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus());
326 oldTagNameToNewTagName.put(tagName, newTagName);
328 }
catch (TskCoreException ex) {
329 handleError(
"Error copying tags", Bundle.PortableCaseReportModule_generateReport_errorCopyingTags(), ex, progressPanel);
334 for (BlackboardArtifact.ARTIFACT_TYPE type : BlackboardArtifact.ARTIFACT_TYPE.values()) {
335 oldArtTypeIdToNewArtTypeId.put(type.getTypeID(), type.getTypeID());
337 for (BlackboardAttribute.ATTRIBUTE_TYPE type : BlackboardAttribute.ATTRIBUTE_TYPE.values()) {
340 }
catch (TskCoreException ex) {
341 handleError(
"Error looking up attribute name " + type.getLabel(),
342 Bundle.PortableCaseReportModule_generateReport_errorLookingUpAttrType(type.getLabel()),
349 for (TagName tagName : tagNames) {
355 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingFiles(tagName.getDisplayName()));
364 }
catch (TskCoreException ex) {
365 handleError(
"Error copying tagged files", Bundle.PortableCaseReportModule_generateReport_errorCopyingFiles(), ex, progressPanel);
371 for (TagName tagName : tagNames) {
377 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingArtifacts(tagName.getDisplayName()));
386 }
catch (TskCoreException ex) {
387 handleError(
"Error copying tagged artifacts", Bundle.PortableCaseReportModule_generateReport_errorCopyingArtifacts(), ex, progressPanel);
392 if (!setNames.isEmpty()) {
394 List<BlackboardArtifact> interestingFiles = currentCase.
getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
395 for (BlackboardArtifact art : interestingFiles) {
402 BlackboardAttribute setAttr = art.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
403 if (setNames.contains(setAttr.getValueString())) {
407 }
catch (TskCoreException ex) {
408 handleError(
"Error copying interesting files", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingFiles(), ex, progressPanel);
413 List<BlackboardArtifact> interestingResults = currentCase.
getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
414 for (BlackboardArtifact art : interestingResults) {
420 BlackboardAttribute setAttr = art.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
421 if (setNames.contains(setAttr.getValueString())) {
425 }
catch (TskCoreException ex) {
426 handleError(
"Error copying interesting results", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingResults(), ex, progressPanel);
442 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingAutopsy());
445 }
catch (IOException ex) {
446 handleError(
"Error copying autopsy", Bundle.PortableCaseReportModule_generateReport_errorCopyingAutopsy(), ex, progressPanel);
452 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_compressingCase());
485 "PortableCaseReportModule.generateCaseUcoReport.errorCreatingReportFolder=Could not make report folder",
486 "PortableCaseReportModule.generateCaseUcoReport.errorGeneratingCaseUcoReport=Problem while generating CASE-UCO report",
487 "PortableCaseReportModule.generateCaseUcoReport.startCaseUcoReportGeneration=Creating a CASE-UCO report of the portable case",
488 "PortableCaseReportModule.generateCaseUcoReport.successCaseUcoReportGeneration=Successfully created a CASE-UCO report of the portable case"
492 Path reportsDirectory = Paths.get(caseFolder.toString(),
"Reports");
493 if (!reportsDirectory.toFile().mkdir()) {
494 logger.log(Level.SEVERE,
"Could not make the report folder... skipping "
495 +
"CASE-UCO report generation for the portable case");
499 Path reportFile = reportsDirectory.resolve(CASE_UCO_FILE_NAME);
501 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_startCaseUcoReportGeneration());
502 try (OutputStream stream =
new FileOutputStream(reportFile.toFile());
503 JsonWriter reportWriter =
new JsonWriter(
new OutputStreamWriter(stream,
"UTF-8"))) {
504 Gson gson =
new GsonBuilder().setPrettyPrinting().create();
505 reportWriter.setIndent(
" ");
506 reportWriter.beginObject();
507 reportWriter.name(
"@graph");
508 reportWriter.beginArray();
516 Path tmpDir = Paths.get(caseTempDirectory, CASE_UCO_TMP_DIR);
517 FileUtils.deleteDirectory(tmpDir.toFile());
518 Files.createDirectory(tmpDir);
520 CaseUcoExporter exporter =
new CaseUcoExporter(currentCase.
getSleuthkitCase());
521 for (JsonElement element : exporter.exportSleuthkitCase()) {
522 gson.toJson(element, reportWriter);
531 for (DataSource dataSource : currentCase.
getSleuthkitCase().getDataSources()) {
534 boolean dataSourceHasBeenIncluded =
false;
537 for (TagName tagName : tagNames) {
540 dataSource, tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
544 dataSource, tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
548 for (BlackboardArtifact bArt : artifactsWithSetName.get(dataSource.getId())) {
549 Content sourceContent = bArt.getParent();
550 dataSourceHasBeenIncluded |=
addUniqueFile(sourceContent, dataSource,
551 tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
556 reportWriter.endArray();
557 reportWriter.endObject();
558 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_successCaseUcoReportGeneration());
559 }
catch (IOException | TskCoreException ex) {
560 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_errorGeneratingCaseUcoReport());
561 logger.log(Level.SEVERE,
"Error encountered while trying to create "
562 +
"CASE-UCO output for portable case.. the portable case will be "
563 +
"completed without a CASE-UCO report.", ex);
573 Multimap<Long, BlackboardArtifact> artifactsWithSetName = ArrayListMultimap.create();
574 if (!setNames.isEmpty()) {
575 List<BlackboardArtifact> allArtifacts = skCase.getBlackboardArtifacts(
576 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
577 allArtifacts.addAll(skCase.getBlackboardArtifacts(
578 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
580 for (BlackboardArtifact bArt : allArtifacts) {
581 BlackboardAttribute setAttr = bArt.getAttribute(
582 new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
583 if (setNames.contains(setAttr.getValueString())) {
584 artifactsWithSetName.put(bArt.getDataSource().getId(), bArt);
588 return artifactsWithSetName;
612 Path tmpDir, Gson gson, CaseUcoExporter exporter, JsonWriter reportWriter,
613 boolean dataSourceHasBeenIncluded)
throws IOException, TskCoreException {
614 if (content instanceof AbstractFile && !(content instanceof DataSource)) {
615 AbstractFile absFile = (AbstractFile) content;
616 Path filePath = tmpDir.resolve(Long.toString(absFile.getId()));
617 if (!absFile.isDir() && !Files.exists(filePath)) {
618 if (!dataSourceHasBeenIncluded) {
619 for (JsonElement element : exporter.exportDataSource(dataSource)) {
620 gson.toJson(element, reportWriter);
625 for (JsonElement element : exporter.exportAbstractFile(absFile, Paths.get(FILE_FOLDER_NAME, subFolder, fileName).toString())) {
626 gson.toJson(element, reportWriter);
628 Files.createFile(filePath);
638 List<String> setNames =
new ArrayList<>();
639 Map<String, Long> setCounts;
643 String innerSelect =
"SELECT (value_text) AS set_name FROM blackboard_attributes WHERE (artifact_type_id = '"
644 + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() +
"' OR artifact_type_id = '"
645 + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() +
"') AND attribute_type_id = '"
646 + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() +
"'";
649 String query =
"set_name, count(1) AS set_count FROM (" + innerSelect +
") set_names GROUP BY set_name";
654 setNames.addAll(setCounts.keySet());
666 "# {0} - case folder",
667 "PortableCaseReportModule.createCase.caseDirExists=Case folder {0} already exists",
668 "PortableCaseReportModule.createCase.errorCreatingCase=Error creating case",
670 "PortableCaseReportModule.createCase.errorCreatingFolder=Error creating folder {0}",
671 "PortableCaseReportModule.createCase.errorStoringMaxIds=Error storing maximum database IDs",})
675 caseFolder = Paths.get(outputDir.toString(),
caseName).toFile();
677 if (caseFolder.exists()) {
678 handleError(
"Case folder " + caseFolder.toString() +
" already exists",
679 Bundle.PortableCaseReportModule_createCase_caseDirExists(caseFolder.toString()), null, progressPanel);
686 }
catch (TskCoreException ex) {
687 handleError(
"Error creating case " + caseName +
" in folder " + caseFolder.toString(),
688 Bundle.PortableCaseReportModule_createCase_errorCreatingCase(), ex, progressPanel);
695 }
catch (TskCoreException ex) {
697 Bundle.PortableCaseReportModule_createCase_errorStoringMaxIds(), ex, progressPanel);
702 copiedFilesFolder = Paths.get(caseFolder.toString(),
FILE_FOLDER_NAME).toFile();
703 if (!copiedFilesFolder.mkdir()) {
704 handleError(
"Error creating folder " + copiedFilesFolder.toString(),
705 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(copiedFilesFolder.toString()), null, progressPanel);
711 File subFolder = Paths.get(copiedFilesFolder.toString(), cat.getDisplayName()).toFile();
712 if (!subFolder.mkdir()) {
713 handleError(
"Error creating folder " + subFolder.toString(),
714 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(subFolder.toString()), null, progressPanel);
719 if (!unknownTypeFolder.mkdir()) {
720 handleError(
"Error creating folder " + unknownTypeFolder.toString(),
721 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(unknownTypeFolder.toString()), null, progressPanel);
734 CaseDbAccessManager currentCaseDbManager = currentCase.
getSleuthkitCase().getCaseDbAccessManager();
736 String tableSchema =
"( table_name TEXT PRIMARY KEY, "
739 portableSkCase.getCaseDbAccessManager().createTable(MAX_ID_TABLE_NAME, tableSchema);
741 currentCaseDbManager.select(
"max(obj_id) as max_id from tsk_objects",
new StoreMaxIdCallback(
"tsk_objects"));
742 currentCaseDbManager.select(
"max(tag_id) as max_id from content_tags",
new StoreMaxIdCallback(
"content_tags"));
743 currentCaseDbManager.select(
"max(tag_id) as max_id from blackboard_artifact_tags",
new StoreMaxIdCallback(
"blackboard_artifact_tags"));
744 currentCaseDbManager.select(
"max(examiner_id) as max_id from tsk_examiners",
new StoreMaxIdCallback(
"tsk_examiners"));
757 CaseDbAccessManager portableDbAccessManager = portableSkCase.getCaseDbAccessManager();
777 for (ContentTag tag : tags) {
784 Content content = tag.getContent();
785 if (content instanceof AbstractFile) {
790 if (!oldTagNameToNewTagName.containsKey(tag.getName())) {
791 throw new TskCoreException(
"TagName map is missing entry for ID " + tag.getName().getId() +
" with display name " + tag.getName().getDisplayName());
793 ContentTagChange newContentTag = portableSkCase.getTaggingManager().addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset());
798 if (!appData.isEmpty()) {
819 currentCase.
getSleuthkitCase().getCaseDbAccessManager().select(query, callback);
820 return callback.getAppData();
836 appData = rs.getString(
"app_data");
837 }
catch (SQLException ex) {
838 logger.log(Level.WARNING,
"Unable to get app_data from result set", ex);
841 }
catch (SQLException ex) {
842 logger.log(Level.WARNING,
"Failed to get next result for app_data", ex);
851 String getAppData() {
865 String insert =
"(content_tag_id, app_data) VALUES (" + newContentTag.getId() +
", '" + appData +
"')";
882 for (BlackboardArtifactTag tag : tags) {
890 Content content = tag.getContent();
894 BlackboardArtifact newArtifact =
copyArtifact(newContentId, tag.getArtifact());
897 copyAttachments(newArtifact, tag.getArtifact(), portableSkCase.getAbstractFileById(newContentId));
903 if (!oldTagNameToNewTagName.containsKey(tag.getName())) {
904 throw new TskCoreException(
"TagName map is missing entry for ID " + tag.getName().getId() +
" with display name " + tag.getName().getDisplayName());
906 portableSkCase.getTaggingManager().addArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment());
922 private BlackboardArtifact
copyArtifact(
long newContentId, BlackboardArtifact artifactToCopy)
throws TskCoreException {
924 if (oldArtifactIdToNewArtifact.containsKey(artifactToCopy.getArtifactID())) {
925 return oldArtifactIdToNewArtifact.get(artifactToCopy.getArtifactID());
929 BlackboardAttribute oldAssociatedAttribute = artifactToCopy.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
930 List<BlackboardAttribute> newAttrs =
new ArrayList<>();
931 if (oldAssociatedAttribute != null) {
932 BlackboardArtifact oldAssociatedArtifact = currentCase.
getSleuthkitCase().getBlackboardArtifact(oldAssociatedAttribute.getValueLong());
933 BlackboardArtifact newAssociatedArtifact =
copyArtifact(newContentId, oldAssociatedArtifact);
934 newAttrs.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT,
935 String.join(
",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID()));
940 BlackboardArtifact newArtifact = portableSkCase.newBlackboardArtifact(newArtifactTypeId, newContentId);
941 List<BlackboardAttribute> oldAttrs = artifactToCopy.getAttributes();
944 for (BlackboardAttribute oldAttr : oldAttrs) {
947 if (SPECIALLY_HANDLED_ATTRS.contains(oldAttr.getAttributeType().getTypeID())) {
952 switch (oldAttr.getValueType()) {
954 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
955 oldAttr.getValueBytes()));
958 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
959 oldAttr.getValueDouble()));
962 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
963 oldAttr.getValueInt()));
967 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
968 oldAttr.getValueLong()));
972 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
973 oldAttr.getValueString()));
976 throw new TskCoreException(
"Unexpected attribute value type found: " + oldAttr.getValueType().getLabel());
980 newArtifact.addAttributes(newAttrs);
982 oldArtifactIdToNewArtifact.put(artifactToCopy.getArtifactID(), newArtifact);
996 if (oldArtTypeIdToNewArtTypeId.containsKey(oldArtifact.getArtifactTypeID())) {
997 return oldArtTypeIdToNewArtTypeId.get(oldArtifact.getArtifactTypeID());
1000 BlackboardArtifact.Type oldCustomType = currentCase.
getSleuthkitCase().getArtifactType(oldArtifact.getArtifactTypeName());
1002 BlackboardArtifact.Type newCustomType = portableSkCase.getBlackboard().getOrAddArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName());
1003 oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID());
1004 return newCustomType.getTypeID();
1005 }
catch (BlackboardException ex) {
1006 throw new TskCoreException(
"Error creating new artifact type " + oldCustomType.getTypeName(), ex);
1019 private BlackboardAttribute.Type
getNewAttributeType(BlackboardAttribute oldAttribute)
throws TskCoreException {
1020 BlackboardAttribute.Type oldAttrType = oldAttribute.getAttributeType();
1026 BlackboardAttribute.Type newCustomType = portableSkCase.getBlackboard().getOrAddAttributeType(oldAttrType.getTypeName(),
1027 oldAttrType.getValueType(), oldAttrType.getDisplayName());
1029 return newCustomType;
1030 }
catch (BlackboardException ex) {
1031 throw new TskCoreException(
"Error creating new attribute type " + oldAttrType.getTypeName(), ex);
1045 @NbBundle.Messages({
1046 "# {0} - File name",
1047 "PortableCaseReportModule.copyContentToPortableCase.copyingFile=Copying file {0}",})
1049 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_copyContentToPortableCase_copyingFile(content.getUniquePath()));
1065 if (oldIdToNewContent.containsKey(content.getId())) {
1066 return oldIdToNewContent.get(content.getId()).getId();
1073 if (content.getParent() != null) {
1078 if (content instanceof BlackboardArtifact) {
1079 BlackboardArtifact artifactToCopy = (BlackboardArtifact) content;
1082 CaseDbTransaction trans = portableSkCase.beginTransaction();
1084 if (content instanceof Image) {
1085 Image image = (Image) content;
1086 newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
1087 new ArrayList<>(), image.getTimeZone(), image.getMd5(), image.getSha1(), image.getSha256(), image.getDeviceId(), trans);
1088 }
else if (content instanceof VolumeSystem) {
1089 VolumeSystem vs = (VolumeSystem) content;
1090 newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
1091 }
else if (content instanceof Volume) {
1092 Volume vs = (Volume) content;
1093 newContent = portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
1094 vs.getDescription(), vs.getFlags(), trans);
1095 }
else if (content instanceof Pool) {
1096 Pool pool = (Pool) content;
1097 newContent = portableSkCase.addPool(parentId, pool.getType(), trans);
1098 }
else if (content instanceof FileSystem) {
1099 FileSystem fs = (FileSystem) content;
1100 newContent = portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
1101 fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(),
1102 fs.getName(), trans);
1103 }
else if (content instanceof BlackboardArtifact) {
1104 BlackboardArtifact artifactToCopy = (BlackboardArtifact) content;
1106 }
else if (content instanceof AbstractFile) {
1107 AbstractFile abstractFile = (AbstractFile) content;
1109 if (abstractFile instanceof LocalFilesDataSource) {
1110 LocalFilesDataSource localFilesDS = (LocalFilesDataSource) abstractFile;
1111 newContent = portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), trans);
1113 if (abstractFile.isDir()) {
1114 newContent = portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
1120 File exportFolder = Paths.get(copiedFilesFolder.toString(), exportSubFolder).toFile();
1121 File localFile =
new File(exportFolder, fileName);
1125 Content oldParent = abstractFile.getParent();
1126 if (!oldIdToNewContent.containsKey(oldParent.getId())) {
1127 throw new TskCoreException(
"Parent of file with ID " + abstractFile.getId() +
" has not been created");
1129 Content newParent = oldIdToNewContent.get(oldParent.getId());
1132 String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
1134 newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
1135 abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
1136 abstractFile.getMd5Hash(), abstractFile.getSha256Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
1137 true, TskData.EncodingType.NONE,
1139 }
catch (IOException ex) {
1140 throw new TskCoreException(
"Error copying file " + abstractFile.getName() +
" with original obj ID "
1141 + abstractFile.getId(), ex);
1146 throw new TskCoreException(
"Trying to copy unexpected Content type " + content.getClass().getName());
1149 }
catch (TskCoreException ex) {
1156 oldIdToNewContent.put(content.getId(), newContent);
1157 newIdToContent.put(newContent.getId(), newContent);
1158 return oldIdToNewContent.get(content.getId()).getId();
1169 private void copyPathID(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact)
throws TskCoreException {
1171 BlackboardAttribute oldPathIdAttr = oldArtifact.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID));
1172 if (oldPathIdAttr != null) {
1174 long oldContentId = oldPathIdAttr.getValueLong();
1175 if (oldContentId > 0) {
1176 Content oldContent = currentCase.
getSleuthkitCase().getContentById(oldContentId);
1178 newArtifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID,
1179 String.join(
",", oldPathIdAttr.getSources()), newContentId));
1193 private void copyAttachments(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact, AbstractFile newFile)
throws TskCoreException {
1195 BlackboardAttribute attachmentsAttr = oldArtifact.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
1196 if (attachmentsAttr != null) {
1198 MessageAttachments msgAttachments = BlackboardJsonAttrUtil.fromAttribute(attachmentsAttr, MessageAttachments.class);
1200 Collection<MessageAttachments.FileAttachment> oldFileAttachments = msgAttachments.getFileAttachments();
1201 List<MessageAttachments.FileAttachment> newFileAttachments =
new ArrayList<>();
1202 for (MessageAttachments.FileAttachment oldFileAttachment : oldFileAttachments) {
1203 long attachedFileObjId = oldFileAttachment.getObjectId();
1204 if (attachedFileObjId >= 0) {
1206 AbstractFile attachedFile = currentCase.
getSleuthkitCase().getAbstractFileById(attachedFileObjId);
1207 if (attachedFile == null) {
1208 throw new TskCoreException(
"Error loading file with object ID " + attachedFileObjId +
" from portable case");
1211 newFileAttachments.add(
new MessageAttachments.FileAttachment(portableSkCase.getAbstractFileById(newFileID)));
1216 String newSourceStr =
"";
1217 List<String> oldSources = attachmentsAttr.getSources();
1218 if (! oldSources.isEmpty()) {
1219 newSourceStr = String.join(
",", oldSources);
1223 CommunicationArtifactsHelper communicationArtifactsHelper =
new CommunicationArtifactsHelper(currentCase.
getSleuthkitCase(),
1224 newSourceStr, newFile, Account.Type.EMAIL);
1225 communicationArtifactsHelper.addAttachments(newArtifact,
new MessageAttachments(newFileAttachments, msgAttachments.getUrlAttachments()));
1227 catch (BlackboardJsonAttrUtil.InvalidJsonException ex) {
1228 throw new TskCoreException(String.format(
"Unable to parse json for MessageAttachments object in artifact: %s", oldArtifact.getName()), ex);
1231 for (Content childContent : oldArtifact.getChildren()) {
1232 if (childContent instanceof AbstractFile) {
1247 if (abstractFile.getMIMEType() == null || abstractFile.getMIMEType().isEmpty()) {
1252 if (cat.getMediaTypes().contains(abstractFile.getMIMEType())) {
1253 return cat.getDisplayName();
1278 return Paths.get(installPath,
"bin", exeName);
1288 return appName +
"64.exe";
1299 private void copyApplication(Path sourceFolder, String destBaseFolder)
throws IOException {
1303 if (!destAppFolder.toFile().exists() && !destAppFolder.toFile().mkdirs()) {
1304 throw new IOException(
"Failed to create directory " + destAppFolder.toString());
1308 FileUtils.copyDirectory(sourceFolder.toFile(), destAppFolder.toFile());
1319 Path filePath = Paths.get(destBaseFolder,
"open.bat");
1322 String casePath =
"..\\" +
caseName;
1323 try (FileWriter writer =
new FileWriter(filePath.toFile())) {
1324 writer.write(exePath +
" \"" + casePath +
"\"");
1332 oldIdToNewContent.clear();
1333 newIdToContent.clear();
1334 oldTagNameToNewTagName.clear();
1335 oldArtTypeIdToNewArtTypeId.clear();
1337 oldArtifactIdToNewArtifact.clear();
1343 copiedFilesFolder = null;
1350 if (portableSkCase != null) {
1351 portableSkCase.close();
1352 portableSkCase = null;
1374 Long maxId = rs.getLong(
"max_id");
1375 String query =
" (table_name, max_id) VALUES ('" + tableName +
"', '" + maxId +
"')";
1376 portableSkCase.getCaseDbAccessManager().insert(MAX_ID_TABLE_NAME, query);
1378 }
catch (SQLException ex) {
1379 logger.log(Level.WARNING,
"Unable to get maximum ID from result set", ex);
1380 }
catch (TskCoreException ex) {
1381 logger.log(Level.WARNING,
"Unable to save maximum ID from result set", ex);
1385 }
catch (SQLException ex) {
1386 logger.log(Level.WARNING,
"Failed to get maximum ID from result set", ex);
1391 @NbBundle.Messages({
1392 "PortableCaseReportModule.compressCase.errorFinding7zip=Could not locate 7-Zip executable",
1393 "# {0} - Temp folder path",
1394 "PortableCaseReportModule.compressCase.errorCreatingTempFolder=Could not create temporary folder {0}",
1395 "PortableCaseReportModule.compressCase.errorCompressingCase=Error compressing case",
1396 "PortableCaseReportModule.compressCase.canceled=Compression canceled by user",})
1402 Path dirToCompress = Paths.get(folderToCompress);
1403 File tempZipFolder = Paths.get(dirToCompress.getParent().toString(),
"temp",
"portableCase" + System.currentTimeMillis()).toFile();
1404 if (!tempZipFolder.mkdirs()) {
1405 handleError(
"Error creating temporary folder " + tempZipFolder.toString(),
1406 Bundle.PortableCaseReportModule_compressCase_errorCreatingTempFolder(tempZipFolder.toString()), null, progressPanel);
1412 if (sevenZipExe == null) {
1413 handleError(
"Error finding 7-Zip exectuable", Bundle.PortableCaseReportModule_compressCase_errorFinding7zip(), null, progressPanel);
1418 String chunkOption =
"";
1423 File zipFile = Paths.get(tempZipFolder.getAbsolutePath(), caseName +
".zip").toFile();
1424 ProcessBuilder procBuilder =
new ProcessBuilder();
1425 procBuilder.command(
1426 sevenZipExe.getAbsolutePath(),
1428 zipFile.getAbsolutePath(),
1429 dirToCompress.toAbsolutePath().toString(),
1434 Process process = procBuilder.start();
1436 while (process.isAlive()) {
1443 int exitCode = process.exitValue();
1444 if (exitCode != 0) {
1446 StringBuilder sb =
new StringBuilder();
1447 try (BufferedReader br =
new BufferedReader(
new InputStreamReader(process.getErrorStream()))) {
1449 while ((line = br.readLine()) != null) {
1450 sb.append(line).append(System.getProperty(
"line.separator"));
1454 handleError(
"Error compressing case\n7-Zip output: " + sb.toString(), Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), null, progressPanel);
1457 }
catch (IOException | InterruptedException ex) {
1458 handleError(
"Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel);
1464 FileUtils.cleanDirectory(dirToCompress.toFile());
1465 FileUtils.copyDirectory(tempZipFolder, dirToCompress.toFile());
1466 FileUtils.deleteDirectory(
new File(tempZipFolder.getParent()));
1467 }
catch (IOException ex) {
1468 handleError(
"Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel);
1485 String executableToFindName = Paths.get(
"7-Zip",
"7z.exe").toString();
1487 if (null == exeFile) {
1491 if (!exeFile.canExecute()) {
1504 private final Map<String, Long>
setCounts =
new HashMap<>();
1511 Long setCount = rs.getLong(
"set_count");
1512 String setName = rs.getString(
"set_name");
1514 setCounts.put(setName, setCount);
1516 }
catch (SQLException ex) {
1517 logger.log(Level.WARNING,
"Unable to get data_source_obj_id or value from result set", ex);
1520 }
catch (SQLException ex) {
1521 logger.log(Level.WARNING,
"Failed to get next result for values by datasource", ex);
static final List< Integer > SPECIALLY_HANDLED_ATTRS
boolean includeApplication()
final Map< Integer, Integer > oldArtTypeIdToNewArtTypeId
void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel)
long copyContent(Content content)
static final Logger logger
int getNewArtifactTypeId(BlackboardArtifact oldArtifact)
static final List< FileTypeCategory > FILE_TYPE_CATEGORIES
static final String MAX_ID_TABLE_NAME
void process(ResultSet rs)
final Map< TagName, TagName > oldTagNameToNewTagName
final Map< Long, Content > oldIdToNewContent
final Map< Long, BlackboardArtifact > oldArtifactIdToNewArtifact
PortableCaseReportModule()
String getTempDirectory()
String getAutopsyExeName()
long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel)
void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)
static final String FILE_FOLDER_NAME
final Map< Integer, BlackboardAttribute.Type > oldAttrTypeIdToNewAttrType
static String getAppName()
void process(ResultSet rs)
void complete(ReportStatus reportStatus)
List< TagName > getSelectedTagNames()
Map< String, Long > getSetCountMap()
static File locate7ZipExecutable()
void copyAttachments(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact, AbstractFile newFile)
Multimap< Long, BlackboardArtifact > getInterestingArtifactsBySetName(SleuthkitCase skCase, List< String > setNames)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
void closePortableCaseDatabase()
List< String > getAllInterestingItemsSets()
void createAppLaunchBatFile(String destBaseFolder)
static final String UNKNOWN_FILE_TYPE_FOLDER
Logger(String name, String resourceBundleName)
void setIndeterminate(boolean indeterminate)
BlackboardAttribute.Type getNewAttributeType(BlackboardAttribute oldAttribute)
void copyPathID(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact)
void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)
void generateReport(String reportPath, PortableCaseReportModuleSettings options, ReportProgressPanel progressPanel)
String getRelativeFilePath()
TagsManager getTagsManager()
static final String CASE_UCO_TMP_DIR
void initializeImageTags(ReportProgressPanel progressPanel)
String getExportSubfolder(AbstractFile abstractFile)
static final String TABLE_SCHEMA_SQLITE
final Map< Long, Content > newIdToContent
SleuthkitCase portableSkCase
static final String TABLE_NAME
final Map< String, Long > setCounts
SleuthkitCase getSleuthkitCase()
List< String > getSelectedSetNames()
BlackboardArtifact copyArtifact(long newContentId, BlackboardArtifact artifactToCopy)
void generateCaseUcoReport(List< TagName > tagNames, List< String > setNames, ReportProgressPanel progressPanel)
void copyApplication(Path sourceFolder, String destBaseFolder)
SleuthkitCase createPortableCase(String caseName, File portableCaseFolder)
boolean areAllTagsSelected()
boolean addUniqueFile(Content content, DataSource dataSource, Path tmpDir, Gson gson, CaseUcoExporter exporter, JsonWriter reportWriter, boolean dataSourceHasBeenIncluded)
static String escapeFileName(String fileName)
boolean compressCase(ReportProgressPanel progressPanel, String folderToCompress)
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
void updateStatusLabel(String statusMessage)
String getImageTagDataForContentTag(ContentTag tag)
static final String CASE_UCO_FILE_NAME
String getSevenZipParam()
boolean areAllSetsSelected()
void addImageTagToPortableCase(ContentTag newContentTag, String appData)
void handleCancellation(ReportProgressPanel progressPanel)
Path getApplicationBasePath()
void createCase(File outputDir, ReportProgressPanel progressPanel)
void process(ResultSet rs)
PortableCaseReportModuleSettings settings