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;
66 import org.
sleuthkit.datamodel.Blackboard.BlackboardException;
81 import org.
sleuthkit.datamodel.OsAccountManager.NotUserSIDException;
87 import org.
sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
89 import org.
sleuthkit.datamodel.TaggingManager.ContentTagChange;
94 import org.
sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper;
95 import org.
sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
96 import org.
sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments;
117 private static final List<Integer>
SPECIALLY_HANDLED_ATTRS = Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID(),
118 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS.getTypeID(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID());
154 "PortableCaseReportModule.getName.name=Portable Case"
158 return Bundle.PortableCaseReportModule_getName_name();
162 "PortableCaseReportModule.getDescription.description=Copies selected items to a new single-user case that can be easily shared"
166 return Bundle.PortableCaseReportModule_getDescription_description();
186 logger.log(Level.INFO,
"Portable case creation canceled by user");
204 logger.log(Level.WARNING, logWarning);
206 logger.log(Level.SEVERE, logWarning, ex);
214 "PortableCaseReportModule.generateReport.verifying=Verifying selected parameters...",
215 "PortableCaseReportModule.generateReport.creatingCase=Creating portable case database...",
216 "PortableCaseReportModule.generateReport.copyingTags=Copying tags...",
218 "PortableCaseReportModule.generateReport.copyingFiles=Copying files tagged as {0}...",
220 "PortableCaseReportModule.generateReport.copyingArtifacts=Copying artifacts tagged as {0}...",
221 "# {0} - output folder",
222 "PortableCaseReportModule.generateReport.outputDirDoesNotExist=Output folder {0} does not exist",
223 "# {0} - output folder",
224 "PortableCaseReportModule.generateReport.outputDirIsNotDir=Output folder {0} is not a folder",
225 "PortableCaseReportModule.generateReport.caseClosed=Current case has been closed",
226 "PortableCaseReportModule.generateReport.interestingItemError=Error loading intersting items",
227 "PortableCaseReportModule.generateReport.errorReadingTags=Error while reading tags from case database",
228 "PortableCaseReportModule.generateReport.errorReadingSets=Error while reading interesting items sets from case database",
229 "PortableCaseReportModule.generateReport.noContentToCopy=No interesting files, results, or tagged items to copy",
230 "PortableCaseReportModule.generateReport.errorCopyingTags=Error copying tags",
231 "PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged files",
232 "PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
233 "PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files",
234 "PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results",
235 "PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table",
236 "PortableCaseReportModule.generateReport.errorCopyingAutopsy=Error copying application",
237 "# {0} - attribute type name",
238 "PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
239 "PortableCaseReportModule.generateReport.compressingCase=Compressing case...",
240 "PortableCaseReportModule_generateReport_copyingAutopsy=Copying application..."
244 this.settings = options;
246 progressPanel.
start();
247 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_verifying());
253 File outputDir =
new File(reportPath);
254 if (!outputDir.exists()) {
255 handleError(
"Output folder " + outputDir.toString() +
" does not exist",
256 Bundle.PortableCaseReportModule_generateReport_outputDirDoesNotExist(outputDir.toString()), null, progressPanel);
260 if (!outputDir.isDirectory()) {
261 handleError(
"Output folder " + outputDir.toString() +
" is not a folder",
262 Bundle.PortableCaseReportModule_generateReport_outputDirIsNotDir(outputDir.toString()), null, progressPanel);
272 Bundle.PortableCaseReportModule_generateReport_caseClosed(), null, progressPanel);
278 outputDir = Paths.get(outputDir.toString(),
caseName).toFile();
281 List<TagName> tagNames;
287 Bundle.PortableCaseReportModule_generateReport_errorReadingTags(), ex, progressPanel);
294 List<String> setNames;
299 handleError(
"Unable to get all interesting items sets",
300 Bundle.PortableCaseReportModule_generateReport_errorReadingSets(), ex, progressPanel);
307 if (tagNames.isEmpty() && setNames.isEmpty()) {
309 Bundle.PortableCaseReportModule_generateReport_noContentToCopy(), null, progressPanel);
315 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_creatingCase());
317 if (portableSkCase == null) {
331 }
catch (TskCoreException ex) {
332 handleError(
"Error creating image tag table", Bundle.PortableCaseReportModule_generateReport_errorCreatingImageTagTable(), ex, progressPanel);
337 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags());
339 for (TagName tagName : tagNames) {
340 TagName newTagName = portableSkCase.addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus());
341 oldTagNameToNewTagName.put(tagName, newTagName);
343 }
catch (TskCoreException ex) {
344 handleError(
"Error copying tags", Bundle.PortableCaseReportModule_generateReport_errorCopyingTags(), ex, progressPanel);
349 for (BlackboardArtifact.ARTIFACT_TYPE type : BlackboardArtifact.ARTIFACT_TYPE.values()) {
350 oldArtTypeIdToNewArtTypeId.put(type.getTypeID(), type.getTypeID());
352 for (BlackboardAttribute.ATTRIBUTE_TYPE type : BlackboardAttribute.ATTRIBUTE_TYPE.values()) {
355 }
catch (TskCoreException ex) {
356 handleError(
"Error looking up attribute name " + type.getLabel(),
357 Bundle.PortableCaseReportModule_generateReport_errorLookingUpAttrType(type.getLabel()),
364 for (TagName tagName : tagNames) {
370 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingFiles(tagName.getDisplayName()));
379 }
catch (TskCoreException ex) {
380 handleError(
"Error copying tagged files", Bundle.PortableCaseReportModule_generateReport_errorCopyingFiles(), ex, progressPanel);
386 for (TagName tagName : tagNames) {
392 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingArtifacts(tagName.getDisplayName()));
401 }
catch (TskCoreException ex) {
402 handleError(
"Error copying tagged artifacts", Bundle.PortableCaseReportModule_generateReport_errorCopyingArtifacts(), ex, progressPanel);
407 if (!setNames.isEmpty()) {
409 List<AnalysisResult> interestingFiles = currentCase.
getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID());
410 for (AnalysisResult art : interestingFiles) {
417 BlackboardAttribute setAttr = art.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
418 if (setNames.contains(setAttr.getValueString())) {
422 }
catch (TskCoreException ex) {
423 handleError(
"Error copying interesting files", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingFiles(), ex, progressPanel);
428 List<AnalysisResult> interestingResults = currentCase.
getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID());
429 for (AnalysisResult art : interestingResults) {
435 BlackboardAttribute setAttr = art.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
436 if (setNames.contains(setAttr.getValueString())) {
440 }
catch (TskCoreException ex) {
441 handleError(
"Error copying interesting results", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingResults(), ex, progressPanel);
457 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingAutopsy());
460 }
catch (IOException ex) {
461 handleError(
"Error copying autopsy", Bundle.PortableCaseReportModule_generateReport_errorCopyingAutopsy(), ex, progressPanel);
467 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_compressingCase());
500 "PortableCaseReportModule.generateCaseUcoReport.errorCreatingReportFolder=Could not make report folder",
501 "PortableCaseReportModule.generateCaseUcoReport.errorGeneratingCaseUcoReport=Problem while generating CASE-UCO report",
502 "PortableCaseReportModule.generateCaseUcoReport.startCaseUcoReportGeneration=Creating a CASE-UCO report of the portable case",
503 "PortableCaseReportModule.generateCaseUcoReport.successCaseUcoReportGeneration=Successfully created a CASE-UCO report of the portable case"
507 Path reportsDirectory = Paths.get(caseFolder.toString(),
"Reports");
508 if (!reportsDirectory.toFile().mkdir()) {
509 logger.log(Level.SEVERE,
"Could not make the report folder... skipping "
510 +
"CASE-UCO report generation for the portable case");
514 Path reportFile = reportsDirectory.resolve(CASE_UCO_FILE_NAME);
516 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_startCaseUcoReportGeneration());
517 try (OutputStream stream =
new FileOutputStream(reportFile.toFile());
518 JsonWriter reportWriter =
new JsonWriter(
new OutputStreamWriter(stream,
"UTF-8"))) {
519 Gson gson =
new GsonBuilder().setPrettyPrinting().create();
520 reportWriter.setIndent(
" ");
521 reportWriter.beginObject();
522 reportWriter.name(
"@graph");
523 reportWriter.beginArray();
531 Path tmpDir = Paths.get(caseTempDirectory, CASE_UCO_TMP_DIR);
532 FileUtils.deleteDirectory(tmpDir.toFile());
533 Files.createDirectory(tmpDir);
535 CaseUcoExporter exporter =
new CaseUcoExporter(currentCase.
getSleuthkitCase());
536 for (JsonElement element : exporter.exportSleuthkitCase()) {
537 gson.toJson(element, reportWriter);
546 for (DataSource dataSource : currentCase.
getSleuthkitCase().getDataSources()) {
549 boolean dataSourceHasBeenIncluded =
false;
552 for (TagName tagName : tagNames) {
555 dataSource, tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
559 dataSource, tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
563 for (BlackboardArtifact bArt : artifactsWithSetName.get(dataSource.getId())) {
564 Content sourceContent = bArt.getParent();
565 dataSourceHasBeenIncluded |=
addUniqueFile(sourceContent, dataSource,
566 tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
571 reportWriter.endArray();
572 reportWriter.endObject();
573 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_successCaseUcoReportGeneration());
574 }
catch (IOException | TskCoreException ex) {
575 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_errorGeneratingCaseUcoReport());
576 logger.log(Level.SEVERE,
"Error encountered while trying to create "
577 +
"CASE-UCO output for portable case.. the portable case will be "
578 +
"completed without a CASE-UCO report.", ex);
588 Multimap<Long, BlackboardArtifact> artifactsWithSetName = ArrayListMultimap.create();
589 if (!setNames.isEmpty()) {
590 List<BlackboardArtifact> allArtifacts = skCase.getBlackboardArtifacts(
591 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
592 allArtifacts.addAll(skCase.getBlackboardArtifacts(
593 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
595 for (BlackboardArtifact bArt : allArtifacts) {
596 BlackboardAttribute setAttr = bArt.getAttribute(
597 new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
598 if (setNames.contains(setAttr.getValueString())) {
599 artifactsWithSetName.put(bArt.getDataSource().getId(), bArt);
603 return artifactsWithSetName;
627 Path tmpDir, Gson gson, CaseUcoExporter exporter, JsonWriter reportWriter,
628 boolean dataSourceHasBeenIncluded)
throws IOException, TskCoreException {
629 if (content instanceof AbstractFile && !(content instanceof DataSource)) {
630 AbstractFile absFile = (AbstractFile) content;
631 Path filePath = tmpDir.resolve(Long.toString(absFile.getId()));
632 if (!absFile.isDir() && !Files.exists(filePath)) {
633 if (!dataSourceHasBeenIncluded) {
634 for (JsonElement element : exporter.exportDataSource(dataSource)) {
635 gson.toJson(element, reportWriter);
640 for (JsonElement element : exporter.exportAbstractFile(absFile, Paths.get(FILE_FOLDER_NAME, subFolder, fileName).toString())) {
641 gson.toJson(element, reportWriter);
643 Files.createFile(filePath);
653 List<String> setNames =
new ArrayList<>();
654 Map<String, Long> setCounts;
658 String innerSelect =
"SELECT (value_text) AS set_name FROM blackboard_attributes WHERE (artifact_type_id = '"
659 + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() +
"' OR artifact_type_id = '"
660 + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() +
"') AND attribute_type_id = '"
661 + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() +
"'";
664 String query =
"set_name, count(1) AS set_count FROM (" + innerSelect +
") set_names GROUP BY set_name";
669 setNames.addAll(setCounts.keySet());
681 "# {0} - case folder",
682 "PortableCaseReportModule.createCase.caseDirExists=Case folder {0} already exists",
683 "PortableCaseReportModule.createCase.errorCreatingCase=Error creating case",
685 "PortableCaseReportModule.createCase.errorCreatingFolder=Error creating folder {0}",
686 "PortableCaseReportModule.createCase.errorStoringMaxIds=Error storing maximum database IDs",})
690 caseFolder = Paths.get(outputDir.toString(),
caseName).toFile();
692 if (caseFolder.exists()) {
693 handleError(
"Case folder " + caseFolder.toString() +
" already exists",
694 Bundle.PortableCaseReportModule_createCase_caseDirExists(caseFolder.toString()), null, progressPanel);
701 }
catch (TskCoreException ex) {
702 handleError(
"Error creating case " + caseName +
" in folder " + caseFolder.toString(),
703 Bundle.PortableCaseReportModule_createCase_errorCreatingCase(), ex, progressPanel);
710 }
catch (TskCoreException ex) {
712 Bundle.PortableCaseReportModule_createCase_errorStoringMaxIds(), ex, progressPanel);
717 copiedFilesFolder = Paths.get(caseFolder.toString(),
FILE_FOLDER_NAME).toFile();
718 if (!copiedFilesFolder.mkdir()) {
719 handleError(
"Error creating folder " + copiedFilesFolder.toString(),
720 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(copiedFilesFolder.toString()), null, progressPanel);
726 File subFolder = Paths.get(copiedFilesFolder.toString(), cat.getDisplayName()).toFile();
727 if (!subFolder.mkdir()) {
728 handleError(
"Error creating folder " + subFolder.toString(),
729 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(subFolder.toString()), null, progressPanel);
734 if (!unknownTypeFolder.mkdir()) {
735 handleError(
"Error creating folder " + unknownTypeFolder.toString(),
736 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(unknownTypeFolder.toString()), null, progressPanel);
749 CaseDbAccessManager currentCaseDbManager = currentCase.
getSleuthkitCase().getCaseDbAccessManager();
751 String tableSchema =
"( table_name TEXT PRIMARY KEY, "
754 portableSkCase.getCaseDbAccessManager().createTable(MAX_ID_TABLE_NAME, tableSchema);
756 currentCaseDbManager.select(
"max(obj_id) as max_id from tsk_objects",
new StoreMaxIdCallback(
"tsk_objects"));
757 currentCaseDbManager.select(
"max(tag_id) as max_id from content_tags",
new StoreMaxIdCallback(
"content_tags"));
758 currentCaseDbManager.select(
"max(tag_id) as max_id from blackboard_artifact_tags",
new StoreMaxIdCallback(
"blackboard_artifact_tags"));
759 currentCaseDbManager.select(
"max(examiner_id) as max_id from tsk_examiners",
new StoreMaxIdCallback(
"tsk_examiners"));
772 CaseDbAccessManager portableDbAccessManager = portableSkCase.getCaseDbAccessManager();
792 for (ContentTag tag : tags) {
799 Content content = tag.getContent();
800 if (content instanceof AbstractFile) {
805 if (!oldTagNameToNewTagName.containsKey(tag.getName())) {
806 throw new TskCoreException(
"TagName map is missing entry for ID " + tag.getName().getId() +
" with display name " + tag.getName().getDisplayName());
808 ContentTagChange newContentTag = portableSkCase.getTaggingManager().addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset());
813 if (!appData.isEmpty()) {
834 currentCase.
getSleuthkitCase().getCaseDbAccessManager().select(query, callback);
835 return callback.getAppData();
851 appData = rs.getString(
"app_data");
852 }
catch (SQLException ex) {
853 logger.log(Level.WARNING,
"Unable to get app_data from result set", ex);
856 }
catch (SQLException ex) {
857 logger.log(Level.WARNING,
"Failed to get next result for app_data", ex);
866 String getAppData() {
880 String insert =
"(content_tag_id, app_data) VALUES (" + newContentTag.getId() +
", '" + appData +
"')";
897 for (BlackboardArtifactTag tag : tags) {
905 Content content = tag.getContent();
909 BlackboardArtifact newArtifact =
copyArtifact(newContentId, tag.getArtifact());
912 copyAttachments(newArtifact, tag.getArtifact(), portableSkCase.getAbstractFileById(newContentId));
918 if (!oldTagNameToNewTagName.containsKey(tag.getName())) {
919 throw new TskCoreException(
"TagName map is missing entry for ID " + tag.getName().getId() +
" with display name " + tag.getName().getDisplayName());
921 portableSkCase.getTaggingManager().addArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment());
937 private BlackboardArtifact
copyArtifact(
long newContentId, BlackboardArtifact artifactToCopy)
throws TskCoreException {
939 if (oldArtifactIdToNewArtifact.containsKey(artifactToCopy.getArtifactID())) {
940 return oldArtifactIdToNewArtifact.get(artifactToCopy.getArtifactID());
944 BlackboardAttribute oldAssociatedAttribute = artifactToCopy.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
945 List<BlackboardAttribute> newAttrs =
new ArrayList<>();
946 if (oldAssociatedAttribute != null) {
947 BlackboardArtifact oldAssociatedArtifact = currentCase.
getSleuthkitCase().getBlackboardArtifact(oldAssociatedAttribute.getValueLong());
948 BlackboardArtifact newAssociatedArtifact =
copyArtifact(newContentId, oldAssociatedArtifact);
949 newAttrs.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT,
950 String.join(
",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID()));
953 List<BlackboardAttribute> oldAttrs = artifactToCopy.getAttributes();
956 for (BlackboardAttribute oldAttr : oldAttrs) {
959 if (SPECIALLY_HANDLED_ATTRS.contains(oldAttr.getAttributeType().getTypeID())) {
964 switch (oldAttr.getValueType()) {
966 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
967 oldAttr.getValueBytes()));
970 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
971 oldAttr.getValueDouble()));
974 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
975 oldAttr.getValueInt()));
979 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
980 oldAttr.getValueLong()));
984 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
985 oldAttr.getValueString()));
988 throw new TskCoreException(
"Unexpected attribute value type found: " + oldAttr.getValueType().getLabel());
993 BlackboardArtifact.Type newArtifactType = portableSkCase.getBlackboard().getArtifactType(newArtifactTypeId);
994 BlackboardArtifact newArtifact;
998 if (!((artifactToCopy instanceof AnalysisResult) || (artifactToCopy instanceof DataArtifact))) {
1000 if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) {
1001 AnalysisResult ar = currentCase.
getSleuthkitCase().getBlackboard().getAnalysisResultById(artifactToCopy.getId());
1003 artifactToCopy = ar;
1006 DataArtifact da = currentCase.
getSleuthkitCase().getBlackboard().getDataArtifactById(artifactToCopy.getId());
1008 artifactToCopy = da;
1011 }
catch (TskCoreException ex) {
1017 if (artifactToCopy instanceof AnalysisResult) {
1018 AnalysisResult analysisResultToCopy = (AnalysisResult) artifactToCopy;
1019 newArtifact = portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId,
1020 newIdToContent.get(newContentId).getDataSource().getId(), analysisResultToCopy.getScore(),
1021 analysisResultToCopy.getConclusion(), analysisResultToCopy.getConfiguration(),
1022 analysisResultToCopy.getJustification(), newAttrs).getAnalysisResult();
1023 }
else if (artifactToCopy instanceof DataArtifact) {
1024 DataArtifact dataArtifactToCopy = (DataArtifact) artifactToCopy;
1025 Long newOsAccountId = null;
1026 if (dataArtifactToCopy.getOsAccountObjectId().isPresent()) {
1027 copyOsAccount(dataArtifactToCopy.getOsAccountObjectId().get());
1028 newOsAccountId = oldOsAccountIdToNewOsAccountId.get((dataArtifactToCopy.getOsAccountObjectId().get()));
1030 newArtifact = portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId,
1031 newIdToContent.get(newContentId).getDataSource().getId(),
1032 newAttrs, newOsAccountId);
1034 if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) {
1035 newArtifact = portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId,
1036 newIdToContent.get(newContentId).getDataSource().getId(), Score.SCORE_NONE,
1037 null, null, null, newAttrs).getAnalysisResult();
1039 newArtifact = portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId,
1040 newIdToContent.get(newContentId).getDataSource().getId(),
1044 }
catch (BlackboardException ex) {
1045 throw new TskCoreException(
"Error copying artifact with ID: " + artifactToCopy.getId());
1048 oldArtifactIdToNewArtifact.put(artifactToCopy.getArtifactID(), newArtifact);
1062 if (oldArtTypeIdToNewArtTypeId.containsKey(oldArtifact.getArtifactTypeID())) {
1063 return oldArtTypeIdToNewArtTypeId.get(oldArtifact.getArtifactTypeID());
1066 BlackboardArtifact.Type oldCustomType = currentCase.
getSleuthkitCase().getArtifactType(oldArtifact.getArtifactTypeName());
1068 BlackboardArtifact.Type newCustomType = portableSkCase.getBlackboard().getOrAddArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName());
1069 oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID());
1070 return newCustomType.getTypeID();
1071 }
catch (BlackboardException ex) {
1072 throw new TskCoreException(
"Error creating new artifact type " + oldCustomType.getTypeName(), ex);
1085 private BlackboardAttribute.Type
getNewAttributeType(BlackboardAttribute oldAttribute)
throws TskCoreException {
1086 BlackboardAttribute.Type oldAttrType = oldAttribute.getAttributeType();
1092 BlackboardAttribute.Type newCustomType = portableSkCase.getBlackboard().getOrAddAttributeType(oldAttrType.getTypeName(),
1093 oldAttrType.getValueType(), oldAttrType.getDisplayName());
1095 return newCustomType;
1096 }
catch (BlackboardException ex) {
1097 throw new TskCoreException(
"Error creating new attribute type " + oldAttrType.getTypeName(), ex);
1111 @NbBundle.Messages({
1112 "# {0} - File name",
1113 "PortableCaseReportModule.copyContentToPortableCase.copyingFile=Copying file {0}",})
1115 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_copyContentToPortableCase_copyingFile(content.getUniquePath()));
1131 if (oldIdToNewContent.containsKey(content.getId())) {
1132 return oldIdToNewContent.get(content.getId()).getId();
1139 if (content.getParent() != null) {
1144 if (content instanceof BlackboardArtifact) {
1145 BlackboardArtifact artifactToCopy = (BlackboardArtifact) content;
1150 Host newHost = null;
1151 if (content instanceof DataSource) {
1152 Host oldHost = ((DataSource)content).getHost();
1153 newHost = portableSkCase.getHostManager().newHost(oldHost.getName());
1157 if (content instanceof AbstractFile) {
1158 AbstractFile file = (AbstractFile) content;
1159 if (file.getOsAccountObjectId().isPresent()) {
1164 CaseDbTransaction trans = portableSkCase.beginTransaction();
1166 if (content instanceof Image) {
1167 Image image = (Image) content;
1168 newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
1169 new ArrayList<>(), image.getTimeZone(), image.getMd5(), image.getSha1(), image.getSha256(), image.getDeviceId(), newHost, trans);
1170 }
else if (content instanceof VolumeSystem) {
1171 VolumeSystem vs = (VolumeSystem) content;
1172 newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
1173 }
else if (content instanceof Volume) {
1174 Volume vs = (Volume) content;
1175 newContent = portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
1176 vs.getDescription(), vs.getFlags(), trans);
1177 }
else if (content instanceof Pool) {
1178 Pool pool = (Pool) content;
1179 newContent = portableSkCase.addPool(parentId, pool.getType(), trans);
1180 }
else if (content instanceof FileSystem) {
1181 FileSystem fs = (FileSystem) content;
1182 newContent = portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
1183 fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(),
1184 fs.getName(), trans);
1185 }
else if (content instanceof BlackboardArtifact) {
1186 BlackboardArtifact artifactToCopy = (BlackboardArtifact) content;
1188 }
else if (content instanceof AbstractFile) {
1189 AbstractFile abstractFile = (AbstractFile) content;
1191 if (abstractFile instanceof LocalFilesDataSource) {
1192 LocalFilesDataSource localFilesDS = (LocalFilesDataSource) abstractFile;
1193 newContent = portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), newHost, trans);
1195 if (abstractFile.isDir()) {
1196 newContent = portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
1202 File exportFolder = Paths.get(copiedFilesFolder.toString(), exportSubFolder).toFile();
1203 File localFile =
new File(exportFolder, fileName);
1207 Content oldParent = abstractFile.getParent();
1208 if (!oldIdToNewContent.containsKey(oldParent.getId())) {
1209 throw new TskCoreException(
"Parent of file with ID " + abstractFile.getId() +
" has not been created");
1211 Content newParent = oldIdToNewContent.get(oldParent.getId());
1214 String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
1216 Long newOsAccountId = null;
1217 if (abstractFile.getOsAccountObjectId().isPresent()) {
1218 newOsAccountId = oldOsAccountIdToNewOsAccountId.get(abstractFile.getOsAccountObjectId().get());
1221 newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
1222 abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
1223 abstractFile.getMd5Hash(), abstractFile.getSha256Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
1224 true, TskData.EncodingType.NONE,
1225 newOsAccountId, abstractFile.getOwnerUid().orElse(null),
1227 }
catch (IOException ex) {
1228 throw new TskCoreException(
"Error copying file " + abstractFile.getName() +
" with original obj ID "
1229 + abstractFile.getId(), ex);
1234 throw new TskCoreException(
"Trying to copy unexpected Content type " + content.getClass().getName());
1237 }
catch (TskCoreException ex) {
1244 oldIdToNewContent.put(content.getId(), newContent);
1245 newIdToContent.put(newContent.getId(), newContent);
1246 return oldIdToNewContent.get(content.getId()).getId();
1257 if (oldOsAccountIdToNewOsAccountId.containsKey(oldOsAccountId)) {
1262 OsAccountManager oldOsAcctManager = currentCase.
getSleuthkitCase().getOsAccountManager();
1263 OsAccount oldOsAccount = oldOsAcctManager.getOsAccountByObjectId(oldOsAccountId);
1266 OsAccountRealmManager oldRealmManager = currentCase.
getSleuthkitCase().getOsAccountRealmManager();
1267 OsAccountRealm oldRealm = oldRealmManager.getRealmByRealmId(oldOsAccount.getRealmId());
1270 if (!oldRealmIdToNewRealm.containsKey(oldOsAccount.getRealmId())) {
1271 OsAccountRealmManager newRealmManager = portableSkCase.getOsAccountRealmManager();
1274 if (oldRealm.getScopeHost().isPresent()) {
1275 host = oldRealm.getScopeHost().get();
1277 if (oldRealm.getScope().equals(OsAccountRealm.RealmScope.DOMAIN)) {
1280 List<Host> hosts = portableSkCase.getHostManager().getAllHosts();
1281 if (hosts.isEmpty()) {
1282 throw new TskCoreException(
"Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() +
" because there are no hosts in the case");
1284 host = hosts.get(0);
1286 throw new TskCoreException(
"Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() +
" because it is non-domain scoped but has no scope host");
1291 String realmName = null;
1292 List<String> names = oldRealm.getRealmNames();
1293 if (!names.isEmpty()) {
1294 realmName = names.get(0);
1298 OsAccountRealm newRealm = newRealmManager.newWindowsRealm(oldRealm.getRealmAddr().orElse(null), realmName, host, oldRealm.getScope());
1299 oldRealmIdToNewRealm.put(oldOsAccount.getRealmId(), newRealm);
1300 }
catch (NotUserSIDException ex) {
1301 throw new TskCoreException(
"Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId(), ex);
1305 OsAccountManager newOsAcctManager = portableSkCase.getOsAccountManager();
1307 OsAccount newOsAccount = newOsAcctManager.newWindowsOsAccount(oldOsAccount.getAddr().orElse(null),
1308 oldOsAccount.getLoginName().orElse(null), oldRealmIdToNewRealm.get(oldOsAccount.getRealmId()));
1309 oldOsAccountIdToNewOsAccountId.put(oldOsAccountId, newOsAccount.getId());
1310 }
catch (NotUserSIDException ex) {
1311 throw new TskCoreException(
"Failed to copy OsAccount with ID=" + oldOsAccount.getId(), ex);
1323 private void copyPathID(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact)
throws TskCoreException {
1325 BlackboardAttribute oldPathIdAttr = oldArtifact.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID));
1326 if (oldPathIdAttr != null) {
1328 long oldContentId = oldPathIdAttr.getValueLong();
1329 if (oldContentId > 0) {
1330 Content oldContent = currentCase.
getSleuthkitCase().getContentById(oldContentId);
1332 newArtifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID,
1333 String.join(
",", oldPathIdAttr.getSources()), newContentId));
1347 private void copyAttachments(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact, AbstractFile newFile)
throws TskCoreException {
1349 BlackboardAttribute attachmentsAttr = oldArtifact.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
1350 if (attachmentsAttr != null) {
1352 MessageAttachments msgAttachments = BlackboardJsonAttrUtil.fromAttribute(attachmentsAttr, MessageAttachments.class);
1354 Collection<MessageAttachments.FileAttachment> oldFileAttachments = msgAttachments.getFileAttachments();
1355 List<MessageAttachments.FileAttachment> newFileAttachments =
new ArrayList<>();
1356 for (MessageAttachments.FileAttachment oldFileAttachment : oldFileAttachments) {
1357 long attachedFileObjId = oldFileAttachment.getObjectId();
1358 if (attachedFileObjId >= 0) {
1360 AbstractFile attachedFile = currentCase.
getSleuthkitCase().getAbstractFileById(attachedFileObjId);
1361 if (attachedFile == null) {
1362 throw new TskCoreException(
"Error loading file with object ID " + attachedFileObjId +
" from portable case");
1365 newFileAttachments.add(
new MessageAttachments.FileAttachment(portableSkCase.getAbstractFileById(newFileID)));
1370 String newSourceStr =
"";
1371 List<String> oldSources = attachmentsAttr.getSources();
1372 if (! oldSources.isEmpty()) {
1373 newSourceStr = String.join(
",", oldSources);
1377 CommunicationArtifactsHelper communicationArtifactsHelper =
new CommunicationArtifactsHelper(currentCase.
getSleuthkitCase(),
1378 newSourceStr, newFile, Account.Type.EMAIL);
1379 communicationArtifactsHelper.addAttachments(newArtifact,
new MessageAttachments(newFileAttachments, msgAttachments.getUrlAttachments()));
1381 catch (BlackboardJsonAttrUtil.InvalidJsonException ex) {
1382 throw new TskCoreException(String.format(
"Unable to parse json for MessageAttachments object in artifact: %s", oldArtifact.getName()), ex);
1385 for (Content childContent : oldArtifact.getChildren()) {
1386 if (childContent instanceof AbstractFile) {
1401 if (abstractFile.getMIMEType() == null || abstractFile.getMIMEType().isEmpty()) {
1406 if (cat.getMediaTypes().contains(abstractFile.getMIMEType())) {
1407 return cat.getDisplayName();
1432 return Paths.get(installPath,
"bin", exeName);
1442 return appName +
"64.exe";
1453 private void copyApplication(Path sourceFolder, String destBaseFolder)
throws IOException {
1457 if (!destAppFolder.toFile().exists() && !destAppFolder.toFile().mkdirs()) {
1458 throw new IOException(
"Failed to create directory " + destAppFolder.toString());
1462 FileUtils.copyDirectory(sourceFolder.toFile(), destAppFolder.toFile());
1473 Path filePath = Paths.get(destBaseFolder,
"open.bat");
1476 String casePath =
"..\\" +
caseName;
1477 try (FileWriter writer =
new FileWriter(filePath.toFile())) {
1478 writer.write(exePath +
" \"" + casePath +
"\"");
1486 oldIdToNewContent.clear();
1487 newIdToContent.clear();
1488 oldTagNameToNewTagName.clear();
1489 oldArtTypeIdToNewArtTypeId.clear();
1491 oldArtifactIdToNewArtifact.clear();
1492 oldOsAccountIdToNewOsAccountId.clear();
1493 oldRealmIdToNewRealm.clear();
1499 copiedFilesFolder = null;
1506 if (portableSkCase != null) {
1507 portableSkCase.close();
1508 portableSkCase = null;
1530 Long maxId = rs.getLong(
"max_id");
1531 String query =
" (table_name, max_id) VALUES ('" + tableName +
"', '" + maxId +
"')";
1532 portableSkCase.getCaseDbAccessManager().insert(MAX_ID_TABLE_NAME, query);
1534 }
catch (SQLException ex) {
1535 logger.log(Level.WARNING,
"Unable to get maximum ID from result set", ex);
1536 }
catch (TskCoreException ex) {
1537 logger.log(Level.WARNING,
"Unable to save maximum ID from result set", ex);
1541 }
catch (SQLException ex) {
1542 logger.log(Level.WARNING,
"Failed to get maximum ID from result set", ex);
1547 @NbBundle.Messages({
1548 "PortableCaseReportModule.compressCase.errorFinding7zip=Could not locate 7-Zip executable",
1549 "# {0} - Temp folder path",
1550 "PortableCaseReportModule.compressCase.errorCreatingTempFolder=Could not create temporary folder {0}",
1551 "PortableCaseReportModule.compressCase.errorCompressingCase=Error compressing case",
1552 "PortableCaseReportModule.compressCase.canceled=Compression canceled by user",})
1558 Path dirToCompress = Paths.get(folderToCompress);
1559 File tempZipFolder = Paths.get(dirToCompress.getParent().toString(),
"temp",
"portableCase" + System.currentTimeMillis()).toFile();
1560 if (!tempZipFolder.mkdirs()) {
1561 handleError(
"Error creating temporary folder " + tempZipFolder.toString(),
1562 Bundle.PortableCaseReportModule_compressCase_errorCreatingTempFolder(tempZipFolder.toString()), null, progressPanel);
1568 if (sevenZipExe == null) {
1569 handleError(
"Error finding 7-Zip exectuable", Bundle.PortableCaseReportModule_compressCase_errorFinding7zip(), null, progressPanel);
1574 String chunkOption =
"";
1579 File zipFile = Paths.get(tempZipFolder.getAbsolutePath(), caseName +
".zip").toFile();
1580 ProcessBuilder procBuilder =
new ProcessBuilder();
1581 procBuilder.command(
1582 sevenZipExe.getAbsolutePath(),
1584 zipFile.getAbsolutePath(),
1585 dirToCompress.toAbsolutePath().toString(),
1590 Process process = procBuilder.start();
1592 while (process.isAlive()) {
1599 int exitCode = process.exitValue();
1600 if (exitCode != 0) {
1602 StringBuilder sb =
new StringBuilder();
1603 try (BufferedReader br =
new BufferedReader(
new InputStreamReader(process.getErrorStream()))) {
1605 while ((line = br.readLine()) != null) {
1606 sb.append(line).append(System.getProperty(
"line.separator"));
1610 handleError(
"Error compressing case\n7-Zip output: " + sb.toString(), Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), null, progressPanel);
1613 }
catch (IOException | InterruptedException ex) {
1614 handleError(
"Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel);
1620 FileUtils.cleanDirectory(dirToCompress.toFile());
1621 FileUtils.copyDirectory(tempZipFolder, dirToCompress.toFile());
1622 FileUtils.deleteDirectory(
new File(tempZipFolder.getParent()));
1623 }
catch (IOException ex) {
1624 handleError(
"Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel);
1641 String executableToFindName = Paths.get(
"7-Zip",
"7z.exe").toString();
1643 if (null == exeFile) {
1647 if (!exeFile.canExecute()) {
1660 private final Map<String, Long>
setCounts =
new HashMap<>();
1667 Long setCount = rs.getLong(
"set_count");
1668 String setName = rs.getString(
"set_name");
1670 setCounts.put(setName, setCount);
1672 }
catch (SQLException ex) {
1673 logger.log(Level.WARNING,
"Unable to get data_source_obj_id or value from result set", ex);
1676 }
catch (SQLException ex) {
1677 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
void copyOsAccount(Long oldOsAccountId)
final Map< Integer, BlackboardAttribute.Type > oldAttrTypeIdToNewAttrType
static String getAppName()
void process(ResultSet rs)
void complete(ReportStatus reportStatus)
List< TagName > getSelectedTagNames()
Map< String, Long > getSetCountMap()
final Map< Long, Long > oldOsAccountIdToNewOsAccountId
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)
final Map< Long, OsAccountRealm > oldRealmIdToNewRealm
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