19package org.sleuthkit.autopsy.report.modules.portablecase;
21import com.google.common.collect.ArrayListMultimap;
22import com.google.common.collect.Multimap;
23import com.google.gson.Gson;
24import com.google.gson.GsonBuilder;
25import com.google.gson.JsonElement;
26import com.google.gson.stream.JsonWriter;
27import org.sleuthkit.autopsy.report.ReportModule;
28import java.util.logging.Level;
29import java.io.BufferedReader;
31import java.io.FileOutputStream;
32import java.io.FileWriter;
33import java.io.InputStreamReader;
34import java.io.IOException;
35import java.io.OutputStream;
36import java.io.OutputStreamWriter;
37import java.nio.file.Files;
38import java.nio.file.Path;
39import java.nio.file.Paths;
40import java.sql.ResultSet;
41import java.sql.SQLException;
42import java.util.ArrayList;
43import java.util.Arrays;
44import java.util.Collection;
45import java.util.HashMap;
48import org.apache.commons.io.FileUtils;
49import org.openide.modules.InstalledFileLocator;
50import org.openide.util.NbBundle;
51import org.sleuthkit.autopsy.casemodule.Case;
52import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
53import org.sleuthkit.autopsy.casemodule.services.TagsManager;
54import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
55import org.sleuthkit.autopsy.core.UserPreferences;
56import org.sleuthkit.autopsy.coreutils.FileUtil;
57import org.sleuthkit.autopsy.coreutils.Logger;
58import org.sleuthkit.autopsy.coreutils.PlatformUtil;
59import org.sleuthkit.autopsy.datamodel.ContentUtils;
60import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
61import org.sleuthkit.autopsy.report.ReportProgressPanel;
62import org.sleuthkit.caseuco.CaseUcoExporter;
63import org.sleuthkit.datamodel.AbstractFile;
64import org.sleuthkit.datamodel.Account;
65import org.sleuthkit.datamodel.AnalysisResult;
66import org.sleuthkit.datamodel.Blackboard.BlackboardException;
67import org.sleuthkit.datamodel.BlackboardArtifact;
68import org.sleuthkit.datamodel.BlackboardArtifactTag;
69import org.sleuthkit.datamodel.BlackboardAttribute;
70import org.sleuthkit.datamodel.CaseDbAccessManager;
71import org.sleuthkit.datamodel.Content;
72import org.sleuthkit.datamodel.ContentTag;
73import org.sleuthkit.datamodel.DataArtifact;
74import org.sleuthkit.datamodel.DataSource;
75import org.sleuthkit.datamodel.FileSystem;
76import org.sleuthkit.datamodel.Host;
77import org.sleuthkit.datamodel.Image;
78import org.sleuthkit.datamodel.LocalFilesDataSource;
79import org.sleuthkit.datamodel.OsAccount;
80import org.sleuthkit.datamodel.OsAccountManager;
81import org.sleuthkit.datamodel.OsAccountManager.NotUserSIDException;
82import org.sleuthkit.datamodel.OsAccountRealm;
83import org.sleuthkit.datamodel.OsAccountRealmManager;
84import org.sleuthkit.datamodel.Pool;
85import org.sleuthkit.datamodel.Score;
86import org.sleuthkit.datamodel.SleuthkitCase;
87import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
88import org.sleuthkit.datamodel.TagName;
89import org.sleuthkit.datamodel.TaggingManager.ContentTagChange;
90import org.sleuthkit.datamodel.TskCoreException;
91import org.sleuthkit.datamodel.TskData;
92import org.sleuthkit.datamodel.Volume;
93import org.sleuthkit.datamodel.VolumeSystem;
94import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper;
95import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
96import 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());
157 "PortableCaseReportModule.getName.name=Portable Case"
161 return Bundle.PortableCaseReportModule_getName_name();
165 "PortableCaseReportModule.getDescription.description=Copies selected items to a new single-user case that can be easily shared"
169 return Bundle.PortableCaseReportModule_getDescription_description();
189 logger.log(Level.INFO,
"Portable case creation canceled by user");
207 logger.log(Level.WARNING, logWarning);
209 logger.log(Level.SEVERE, logWarning, ex);
217 "PortableCaseReportModule.generateReport.verifying=Verifying selected parameters...",
218 "PortableCaseReportModule.generateReport.creatingCase=Creating portable case database...",
219 "PortableCaseReportModule.generateReport.copyingTags=Copying tags...",
221 "PortableCaseReportModule.generateReport.copyingFiles=Copying files tagged as {0}...",
223 "PortableCaseReportModule.generateReport.copyingArtifacts=Copying artifacts tagged as {0}...",
224 "# {0} - output folder",
225 "PortableCaseReportModule.generateReport.outputDirDoesNotExist=Output folder {0} does not exist",
226 "# {0} - output folder",
227 "PortableCaseReportModule.generateReport.outputDirIsNotDir=Output folder {0} is not a folder",
228 "PortableCaseReportModule.generateReport.caseClosed=Current case has been closed",
229 "PortableCaseReportModule.generateReport.interestingItemError=Error loading intersting items",
230 "PortableCaseReportModule.generateReport.errorReadingTags=Error while reading tags from case database",
231 "PortableCaseReportModule.generateReport.errorReadingSets=Error while reading interesting items sets from case database",
232 "PortableCaseReportModule.generateReport.noContentToCopy=No interesting files, results, or tagged items to copy",
233 "PortableCaseReportModule.generateReport.errorCopyingTags=Error copying tags",
234 "PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged files",
235 "PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
236 "PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files",
237 "PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results",
238 "PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table",
239 "PortableCaseReportModule.generateReport.errorCopyingAutopsy=Error copying application",
240 "# {0} - attribute type name",
241 "PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
242 "PortableCaseReportModule.generateReport.compressingCase=Compressing case...",
243 "PortableCaseReportModule_generateReport_copyingAutopsy=Copying application..."
249 @SuppressWarnings(
"deprecation")
251 this.settings = options;
253 progressPanel.
start();
254 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_verifying());
260 File outputDir =
new File(reportPath);
261 if (!outputDir.exists()) {
262 handleError(
"Output folder " + outputDir.toString() +
" does not exist",
263 Bundle.PortableCaseReportModule_generateReport_outputDirDoesNotExist(outputDir.toString()),
null, progressPanel);
267 if (!outputDir.isDirectory()) {
268 handleError(
"Output folder " + outputDir.toString() +
" is not a folder",
269 Bundle.PortableCaseReportModule_generateReport_outputDirIsNotDir(outputDir.toString()),
null, progressPanel);
279 Bundle.PortableCaseReportModule_generateReport_caseClosed(),
null, progressPanel);
285 outputDir = Paths.get(outputDir.toString(),
caseName).toFile();
288 List<TagName> tagNames;
294 Bundle.PortableCaseReportModule_generateReport_errorReadingTags(), ex, progressPanel);
301 List<String> setNames;
306 handleError(
"Unable to get all interesting items sets",
307 Bundle.PortableCaseReportModule_generateReport_errorReadingSets(), ex, progressPanel);
314 if (tagNames.isEmpty() && setNames.isEmpty()) {
316 Bundle.PortableCaseReportModule_generateReport_noContentToCopy(),
null, progressPanel);
322 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_creatingCase());
338 }
catch (TskCoreException ex) {
339 handleError(
"Error creating image tag table", Bundle.PortableCaseReportModule_generateReport_errorCreatingImageTagTable(), ex, progressPanel);
344 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags());
346 for (TagName tagName : tagNames) {
347 TagName newTagName =
portableSkCase.getTaggingManager().addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getTagType());
350 }
catch (TskCoreException ex) {
351 handleError(
"Error copying tags", Bundle.PortableCaseReportModule_generateReport_errorCopyingTags(), ex, progressPanel);
356 for (BlackboardArtifact.ARTIFACT_TYPE type : BlackboardArtifact.ARTIFACT_TYPE.values()) {
359 for (BlackboardAttribute.ATTRIBUTE_TYPE type : BlackboardAttribute.ATTRIBUTE_TYPE.values()) {
362 }
catch (TskCoreException ex) {
363 handleError(
"Error looking up attribute name " + type.getLabel(),
364 Bundle.PortableCaseReportModule_generateReport_errorLookingUpAttrType(type.getLabel()),
371 for (TagName tagName : tagNames) {
377 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingFiles(tagName.getDisplayName()));
386 }
catch (TskCoreException ex) {
387 handleError(
"Error copying tagged files", Bundle.PortableCaseReportModule_generateReport_errorCopyingFiles(), ex, progressPanel);
393 for (TagName tagName : tagNames) {
399 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingArtifacts(tagName.getDisplayName()));
408 }
catch (TskCoreException ex) {
409 handleError(
"Error copying tagged artifacts", Bundle.PortableCaseReportModule_generateReport_errorCopyingArtifacts(), ex, progressPanel);
414 if (!setNames.isEmpty()) {
416 List<AnalysisResult> interestingFiles =
currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID());
417 for (AnalysisResult art : interestingFiles) {
424 BlackboardAttribute setAttr = art.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
425 if (setNames.contains(setAttr.getValueString())) {
429 }
catch (TskCoreException ex) {
430 handleError(
"Error copying interesting files", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingFiles(), ex, progressPanel);
435 List<AnalysisResult> interestingResults =
currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID());
436 for (AnalysisResult art : interestingResults) {
442 BlackboardAttribute setAttr = art.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
443 if (setNames.contains(setAttr.getValueString())) {
447 }
catch (TskCoreException ex) {
448 handleError(
"Error copying interesting results", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingResults(), ex, progressPanel);
453 List<AnalysisResult> interestingResults =
currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_ITEM.getTypeID());
454 for (AnalysisResult art : interestingResults) {
460 BlackboardAttribute setAttr = art.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
461 if (setNames.contains(setAttr.getValueString())) {
465 }
catch (TskCoreException ex) {
466 handleError(
"Error copying interesting items", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingResults(), ex, progressPanel);
482 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingAutopsy());
485 }
catch (IOException ex) {
486 handleError(
"Error copying autopsy", Bundle.PortableCaseReportModule_generateReport_errorCopyingAutopsy(), ex, progressPanel);
492 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_compressingCase());
525 "PortableCaseReportModule.generateCaseUcoReport.errorCreatingReportFolder=Could not make report folder",
526 "PortableCaseReportModule.generateCaseUcoReport.errorGeneratingCaseUcoReport=Problem while generating CASE-UCO report",
527 "PortableCaseReportModule.generateCaseUcoReport.startCaseUcoReportGeneration=Creating a CASE-UCO report of the portable case",
528 "PortableCaseReportModule.generateCaseUcoReport.successCaseUcoReportGeneration=Successfully created a CASE-UCO report of the portable case"
532 Path reportsDirectory = Paths.get(
caseFolder.toString(),
"Reports");
533 if (!reportsDirectory.toFile().mkdir()) {
534 logger.log(Level.SEVERE,
"Could not make the report folder... skipping "
535 +
"CASE-UCO report generation for the portable case");
541 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_startCaseUcoReportGeneration());
542 try (OutputStream stream =
new FileOutputStream(reportFile.toFile());
543 JsonWriter reportWriter =
new JsonWriter(
new OutputStreamWriter(stream,
"UTF-8"))) {
544 Gson gson =
new GsonBuilder().setPrettyPrinting().create();
545 reportWriter.setIndent(
" ");
546 reportWriter.beginObject();
547 reportWriter.name(
"@graph");
548 reportWriter.beginArray();
550 String caseTempDirectory =
currentCase.getTempDirectory();
551 SleuthkitCase skCase =
currentCase.getSleuthkitCase();
557 FileUtils.deleteDirectory(tmpDir.toFile());
558 Files.createDirectory(tmpDir);
560 CaseUcoExporter exporter =
new CaseUcoExporter(
currentCase.getSleuthkitCase());
561 for (JsonElement element : exporter.exportSleuthkitCase()) {
562 gson.toJson(element, reportWriter);
571 for (DataSource dataSource :
currentCase.getSleuthkitCase().getDataSources()) {
574 boolean dataSourceHasBeenIncluded =
false;
577 for (TagName tagName : tagNames) {
580 dataSource, tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
584 dataSource, tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
588 for (BlackboardArtifact bArt : artifactsWithSetName.get(dataSource.getId())) {
589 Content sourceContent = bArt.getParent();
590 dataSourceHasBeenIncluded |=
addUniqueFile(sourceContent, dataSource,
591 tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
596 reportWriter.endArray();
597 reportWriter.endObject();
598 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_successCaseUcoReportGeneration());
599 }
catch (IOException | TskCoreException ex) {
600 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_errorGeneratingCaseUcoReport());
601 logger.log(Level.SEVERE,
"Error encountered while trying to create "
602 +
"CASE-UCO output for portable case.. the portable case will be "
603 +
"completed without a CASE-UCO report.", ex);
615 @SuppressWarnings(
"deprecation")
617 Multimap<Long, BlackboardArtifact> artifactsWithSetName = ArrayListMultimap.create();
618 if (!setNames.isEmpty()) {
619 List<BlackboardArtifact> allArtifacts = skCase.getBlackboardArtifacts(
620 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
621 allArtifacts.addAll(skCase.getBlackboardArtifacts(
622 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
623 allArtifacts.addAll(skCase.getBlackboardArtifacts(
624 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ITEM));
626 for (BlackboardArtifact bArt : allArtifacts) {
627 BlackboardAttribute setAttr = bArt.getAttribute(
628 new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
629 if (setNames.contains(setAttr.getValueString())) {
630 artifactsWithSetName.put(bArt.getDataSource().getId(), bArt);
634 return artifactsWithSetName;
658 Path tmpDir, Gson gson, CaseUcoExporter exporter, JsonWriter reportWriter,
659 boolean dataSourceHasBeenIncluded)
throws IOException, TskCoreException {
660 if (content instanceof AbstractFile && !(content instanceof DataSource)) {
661 AbstractFile absFile = (AbstractFile) content;
662 Path filePath = tmpDir.resolve(Long.toString(absFile.getId()));
663 if (!absFile.isDir() && !Files.exists(filePath)) {
664 if (!dataSourceHasBeenIncluded) {
665 for (JsonElement element : exporter.exportDataSource(dataSource)) {
666 gson.toJson(element, reportWriter);
671 for (JsonElement element : exporter.exportAbstractFile(absFile, Paths.get(
FILE_FOLDER_NAME, subFolder, fileName).toString())) {
672 gson.toJson(element, reportWriter);
674 Files.createFile(filePath);
685 @SuppressWarnings(
"deprecation")
689 List<String> setNames =
new ArrayList<>();
690 Map<String, Long> setCounts;
694 String innerSelect =
"SELECT (value_text) AS set_name FROM blackboard_attributes WHERE (artifact_type_id = '"
695 + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() +
"' OR artifact_type_id = '"
696 + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ITEM.getTypeID() +
"' OR artifact_type_id = '"
697 + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() +
"') AND attribute_type_id = '"
698 + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() +
"'";
701 String query =
"set_name, count(1) AS set_count FROM (" + innerSelect +
") set_names GROUP BY set_name";
706 setNames.addAll(setCounts.keySet());
718 "# {0} - case folder",
719 "PortableCaseReportModule.createCase.caseDirExists=Case folder {0} already exists",
720 "PortableCaseReportModule.createCase.errorCreatingCase=Error creating case",
722 "PortableCaseReportModule.createCase.errorCreatingFolder=Error creating folder {0}",
723 "PortableCaseReportModule.createCase.errorStoringMaxIds=Error storing maximum database IDs",})
731 Bundle.PortableCaseReportModule_createCase_caseDirExists(
caseFolder.toString()),
null, progressPanel);
738 }
catch (TskCoreException ex) {
740 Bundle.PortableCaseReportModule_createCase_errorCreatingCase(), ex, progressPanel);
747 }
catch (TskCoreException ex) {
749 Bundle.PortableCaseReportModule_createCase_errorStoringMaxIds(), ex, progressPanel);
757 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(
copiedFilesFolder.toString()),
null, progressPanel);
763 File subFolder = Paths.get(
copiedFilesFolder.toString(), cat.getDisplayName()).toFile();
764 if (!subFolder.mkdir()) {
765 handleError(
"Error creating folder " + subFolder.toString(),
766 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(subFolder.toString()),
null, progressPanel);
771 if (!unknownTypeFolder.mkdir()) {
772 handleError(
"Error creating folder " + unknownTypeFolder.toString(),
773 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(unknownTypeFolder.toString()),
null, progressPanel);
786 CaseDbAccessManager currentCaseDbManager =
currentCase.getSleuthkitCase().getCaseDbAccessManager();
788 String tableSchema =
"( table_name TEXT PRIMARY KEY, "
793 currentCaseDbManager.select(
"max(obj_id) as max_id from tsk_objects",
new StoreMaxIdCallback(
"tsk_objects"));
794 currentCaseDbManager.select(
"max(tag_id) as max_id from content_tags",
new StoreMaxIdCallback(
"content_tags"));
795 currentCaseDbManager.select(
"max(tag_id) as max_id from blackboard_artifact_tags",
new StoreMaxIdCallback(
"blackboard_artifact_tags"));
796 currentCaseDbManager.select(
"max(examiner_id) as max_id from tsk_examiners",
new StoreMaxIdCallback(
"tsk_examiners"));
809 CaseDbAccessManager portableDbAccessManager =
portableSkCase.getCaseDbAccessManager();
826 List<ContentTag>
tags =
currentCase.getServices().getTagsManager().getContentTagsByTagName(oldTagName);
829 for (ContentTag tag :
tags) {
836 Content content = tag.getContent();
837 if (content instanceof AbstractFile) {
843 throw new TskCoreException(
"TagName map is missing entry for ID " + tag.getName().getId() +
" with display name " + tag.getName().getDisplayName());
850 if (!appData.isEmpty()) {
871 currentCase.getSleuthkitCase().getCaseDbAccessManager().select(query, callback);
872 return callback.getAppData();
888 appData = rs.getString(
"app_data");
889 }
catch (SQLException ex) {
890 logger.log(Level.WARNING,
"Unable to get app_data from result set", ex);
893 }
catch (SQLException ex) {
894 logger.log(Level.WARNING,
"Failed to get next result for app_data", ex);
903 String getAppData() {
917 String insert =
"(content_tag_id, app_data) VALUES (" + newContentTag.getId() +
", '" + appData +
"')";
931 List<BlackboardArtifactTag>
tags =
currentCase.getServices().getTagsManager().getBlackboardArtifactTagsByTagName(oldTagName);
934 for (BlackboardArtifactTag tag :
tags) {
942 Content content = tag.getContent();
946 BlackboardArtifact newArtifact =
copyArtifact(newContentId, tag.getArtifact());
956 throw new TskCoreException(
"TagName map is missing entry for ID " + tag.getName().getId() +
" with display name " + tag.getName().getDisplayName());
974 private BlackboardArtifact
copyArtifact(
long newContentId, BlackboardArtifact artifactToCopy)
throws TskCoreException {
981 BlackboardAttribute oldAssociatedAttribute = artifactToCopy.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
982 List<BlackboardAttribute> newAttrs =
new ArrayList<>();
983 if (oldAssociatedAttribute !=
null) {
984 BlackboardArtifact oldAssociatedArtifact =
currentCase.getSleuthkitCase().getBlackboardArtifact(oldAssociatedAttribute.getValueLong());
985 BlackboardArtifact newAssociatedArtifact =
copyArtifact(newContentId, oldAssociatedArtifact);
986 newAttrs.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT,
987 String.join(
",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID()));
990 List<BlackboardAttribute> oldAttrs = artifactToCopy.getAttributes();
993 for (BlackboardAttribute oldAttr : oldAttrs) {
1001 switch (oldAttr.getValueType()) {
1003 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
1004 oldAttr.getValueBytes()));
1007 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
1008 oldAttr.getValueDouble()));
1011 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
1012 oldAttr.getValueInt()));
1016 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
1017 oldAttr.getValueLong()));
1021 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
1022 oldAttr.getValueString()));
1025 throw new TskCoreException(
"Unexpected attribute value type found: " + oldAttr.getValueType().getLabel());
1031 Long newDataSourceId;
1035 newDataSourceId =
newIdToContent.get(newContentId).getDataSource().getId();
1038 if (artifactToCopy.getDataSource() ==
null) {
1040 throw new TskCoreException(
"Can not copy artifact with ID: " + artifactToCopy.getArtifactID() +
" because it is not associated with a data source");
1042 newDataSourceId =
copyContent(artifactToCopy.getDataSource());
1047 BlackboardArtifact.Type newArtifactType =
portableSkCase.getBlackboard().getArtifactType(newArtifactTypeId);
1048 BlackboardArtifact newArtifact;
1052 if (!((artifactToCopy instanceof AnalysisResult) || (artifactToCopy instanceof DataArtifact))) {
1054 if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) {
1055 AnalysisResult ar =
currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultById(artifactToCopy.getId());
1057 artifactToCopy = ar;
1060 DataArtifact da =
currentCase.getSleuthkitCase().getBlackboard().getDataArtifactById(artifactToCopy.getId());
1062 artifactToCopy = da;
1065 }
catch (TskCoreException ex) {
1071 if (artifactToCopy instanceof AnalysisResult) {
1072 AnalysisResult analysisResultToCopy = (AnalysisResult) artifactToCopy;
1073 newArtifact =
portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId,
1074 newDataSourceId, analysisResultToCopy.getScore(),
1075 analysisResultToCopy.getConclusion(), analysisResultToCopy.getConfiguration(),
1076 analysisResultToCopy.getJustification(), newAttrs).getAnalysisResult();
1077 }
else if (artifactToCopy instanceof DataArtifact) {
1078 DataArtifact dataArtifactToCopy = (DataArtifact) artifactToCopy;
1079 Long newOsAccountId =
null;
1080 if (dataArtifactToCopy.getOsAccountObjectId().isPresent()) {
1081 copyOsAccount(dataArtifactToCopy.getOsAccountObjectId().get());
1084 newArtifact =
portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId,
1086 newAttrs, newOsAccountId);
1088 if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) {
1089 newArtifact =
portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId,
1090 newDataSourceId, Score.SCORE_NONE,
1091 null,
null,
null, newAttrs).getAnalysisResult();
1093 newArtifact =
portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId,
1098 }
catch (BlackboardException ex) {
1099 throw new TskCoreException(
"Error copying artifact with ID: " + artifactToCopy.getId());
1120 BlackboardArtifact.Type oldCustomType =
currentCase.getSleuthkitCase().getBlackboard().getArtifactType(oldArtifact.getArtifactTypeName());
1122 BlackboardArtifact.Type newCustomType =
portableSkCase.getBlackboard().getOrAddArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName());
1124 return newCustomType.getTypeID();
1125 }
catch (BlackboardException ex) {
1126 throw new TskCoreException(
"Error creating new artifact type " + oldCustomType.getTypeName(), ex);
1139 private BlackboardAttribute.Type
getNewAttributeType(BlackboardAttribute oldAttribute)
throws TskCoreException {
1140 BlackboardAttribute.Type oldAttrType = oldAttribute.getAttributeType();
1146 BlackboardAttribute.Type newCustomType =
portableSkCase.getBlackboard().getOrAddAttributeType(oldAttrType.getTypeName(),
1147 oldAttrType.getValueType(), oldAttrType.getDisplayName());
1149 return newCustomType;
1150 }
catch (BlackboardException ex) {
1151 throw new TskCoreException(
"Error creating new attribute type " + oldAttrType.getTypeName(), ex);
1165 @NbBundle.Messages({
1166 "# {0} - File name",
1167 "PortableCaseReportModule.copyContentToPortableCase.copyingFile=Copying file {0}",})
1169 progressPanel.
updateStatusLabel(Bundle.PortableCaseReportModule_copyContentToPortableCase_copyingFile(content.getUniquePath()));
1193 if (content.getParent() !=
null) {
1198 if (content instanceof BlackboardArtifact) {
1199 BlackboardArtifact artifactToCopy = (BlackboardArtifact) content;
1201 }
else if (content instanceof OsAccount) {
1205 Host newHost =
null;
1206 if (content instanceof DataSource) {
1207 newHost =
copyHost(((DataSource) content).getHost());
1211 if (content instanceof AbstractFile) {
1212 AbstractFile
file = (AbstractFile) content;
1213 if (
file.getOsAccountObjectId().isPresent()) {
1222 if (content instanceof Image) {
1223 md5 = ((Image) content).getMd5();
1224 sha1 = ((Image) content).getSha1();
1225 sha256 = ((Image) content).getSha256();
1230 if (content instanceof Image) {
1231 Image image = (Image) content;
1232 newContent =
portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
1233 new ArrayList<>(), image.getTimeZone(), md5, sha1, sha256, image.getDeviceId(), newHost, trans);
1234 }
else if (content instanceof VolumeSystem) {
1235 VolumeSystem vs = (VolumeSystem) content;
1236 newContent =
portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
1237 }
else if (content instanceof Volume) {
1238 Volume vs = (Volume) content;
1239 newContent =
portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
1240 vs.getDescription(), vs.getFlags(), trans);
1241 }
else if (content instanceof Pool) {
1242 Pool pool = (Pool) content;
1243 newContent =
portableSkCase.addPool(parentId, pool.getType(), trans);
1244 }
else if (content instanceof FileSystem) {
1245 FileSystem fs = (FileSystem) content;
1246 newContent =
portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
1247 fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(),
1248 fs.getName(), trans);
1249 }
else if (content instanceof BlackboardArtifact) {
1250 BlackboardArtifact artifactToCopy = (BlackboardArtifact) content;
1252 }
else if (content instanceof AbstractFile) {
1253 AbstractFile abstractFile = (AbstractFile) content;
1255 if (abstractFile instanceof LocalFilesDataSource) {
1256 LocalFilesDataSource localFilesDS = (LocalFilesDataSource) abstractFile;
1257 newContent =
portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), newHost, trans);
1259 if (abstractFile.isDir()) {
1260 newContent =
portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
1266 File exportFolder = Paths.get(
copiedFilesFolder.toString(), exportSubFolder).toFile();
1267 File localFile =
new File(exportFolder, fileName);
1271 Content oldParent = abstractFile.getParent();
1273 throw new TskCoreException(
"Parent of file with ID " + abstractFile.getId() +
" has not been created");
1278 String relativePath =
FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
1280 Long newOsAccountId =
null;
1281 if (abstractFile.getOsAccountObjectId().isPresent()) {
1285 newContent =
portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
1286 abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
1287 abstractFile.getMd5Hash(), abstractFile.getSha256Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
1288 true, TskData.EncodingType.NONE,
1289 newOsAccountId, abstractFile.getOwnerUid().orElse(
null),
1291 }
catch (IOException ex) {
1292 throw new TskCoreException(
"Error copying file " + abstractFile.getName() +
" with original obj ID "
1293 + abstractFile.getId(), ex);
1298 throw new TskCoreException(
"Trying to copy unexpected Content type " + content.getClass().getName());
1301 }
catch (TskCoreException ex) {
1323 private Host
copyHost(Host oldHost)
throws TskCoreException {
1328 newHost =
portableSkCase.getHostManager().newHost(oldHost.getName());
1347 OsAccountManager oldOsAcctManager =
currentCase.getSleuthkitCase().getOsAccountManager();
1348 OsAccount oldOsAccount = oldOsAcctManager.getOsAccountByObjectId(oldOsAccountId);
1351 OsAccountRealmManager oldRealmManager =
currentCase.getSleuthkitCase().getOsAccountRealmManager();
1352 OsAccountRealm oldRealm = oldRealmManager.getRealmByRealmId(oldOsAccount.getRealmId());
1356 OsAccountRealmManager newRealmManager =
portableSkCase.getOsAccountRealmManager();
1358 Host newHost =
null;
1359 if (oldRealm.getScopeHost().isPresent()) {
1360 Host host = oldRealm.getScopeHost().get();
1363 if (oldRealm.getScope().equals(OsAccountRealm.RealmScope.DOMAIN)) {
1367 throw new TskCoreException(
"Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() +
" - can not currently handle domain-scoped hosts");
1369 throw new TskCoreException(
"Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() +
" because it is non-domain scoped but has no scope host");
1374 String realmName =
null;
1375 List<String> names = oldRealm.getRealmNames();
1376 if (!names.isEmpty()) {
1377 realmName = names.get(0);
1381 OsAccountRealm newRealm = newRealmManager.newWindowsRealm(oldOsAccount.getAddr().orElse(
null), realmName, newHost, oldRealm.getScope());
1383 }
catch (NotUserSIDException ex) {
1384 throw new TskCoreException(
"Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId(), ex);
1388 OsAccountManager newOsAcctManager =
portableSkCase.getOsAccountManager();
1390 OsAccount newOsAccount = newOsAcctManager.newWindowsOsAccount(oldOsAccount.getAddr().orElse(
null),
1391 oldOsAccount.getLoginName().orElse(
null),
oldRealmIdToNewRealm.get(oldOsAccount.getRealmId()));
1393 return newOsAccount;
1394 }
catch (NotUserSIDException ex) {
1395 throw new TskCoreException(
"Failed to copy OsAccount with ID=" + oldOsAccount.getId(), ex);
1408 private void copyPathID(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact)
throws TskCoreException {
1410 BlackboardAttribute oldPathIdAttr = oldArtifact.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID));
1411 if (oldPathIdAttr !=
null) {
1413 long oldContentId = oldPathIdAttr.getValueLong();
1414 if (oldContentId > 0) {
1415 Content oldContent =
currentCase.getSleuthkitCase().getContentById(oldContentId);
1417 newArtifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID,
1418 String.join(
",", oldPathIdAttr.getSources()), newContentId));
1434 private void copyAttachments(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact, AbstractFile newFile)
throws TskCoreException {
1436 BlackboardAttribute attachmentsAttr = oldArtifact.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
1437 if (attachmentsAttr !=
null) {
1439 MessageAttachments msgAttachments = BlackboardJsonAttrUtil.fromAttribute(attachmentsAttr, MessageAttachments.class);
1441 Collection<MessageAttachments.FileAttachment> oldFileAttachments = msgAttachments.getFileAttachments();
1442 List<MessageAttachments.FileAttachment> newFileAttachments =
new ArrayList<>();
1443 for (MessageAttachments.FileAttachment oldFileAttachment : oldFileAttachments) {
1444 long attachedFileObjId = oldFileAttachment.getObjectId();
1445 if (attachedFileObjId >= 0) {
1447 AbstractFile attachedFile =
currentCase.getSleuthkitCase().getAbstractFileById(attachedFileObjId);
1448 if (attachedFile ==
null) {
1449 throw new TskCoreException(
"Error loading file with object ID " + attachedFileObjId +
" from portable case");
1452 newFileAttachments.add(
new MessageAttachments.FileAttachment(
portableSkCase.getAbstractFileById(newFileID)));
1457 String newSourceStr =
"";
1458 List<String> oldSources = attachmentsAttr.getSources();
1459 if (!oldSources.isEmpty()) {
1460 newSourceStr = String.join(
",", oldSources);
1464 CommunicationArtifactsHelper communicationArtifactsHelper =
new CommunicationArtifactsHelper(
currentCase.getSleuthkitCase(),
1465 newSourceStr, newFile, Account.Type.EMAIL,
null);
1466 communicationArtifactsHelper.addAttachments(newArtifact,
new MessageAttachments(newFileAttachments, msgAttachments.getUrlAttachments()));
1467 }
catch (BlackboardJsonAttrUtil.InvalidJsonException ex) {
1468 throw new TskCoreException(String.format(
"Unable to parse json for MessageAttachments object in artifact: %s", oldArtifact.getName()), ex);
1471 for (Content childContent : oldArtifact.getChildren()) {
1472 if (childContent instanceof AbstractFile) {
1487 if (abstractFile.getMIMEType() ==
null || abstractFile.getMIMEType().isEmpty()) {
1492 if (cat.getMediaTypes().contains(abstractFile.getMIMEType())) {
1493 return cat.getDisplayName();
1518 return Paths.get(installPath,
"bin", exeName);
1528 return appName +
"64.exe";
1539 private void copyApplication(Path sourceFolder, String destBaseFolder)
throws IOException {
1543 if (!destAppFolder.toFile().exists() && !destAppFolder.toFile().mkdirs()) {
1544 throw new IOException(
"Failed to create directory " + destAppFolder.toString());
1548 FileUtils.copyDirectory(sourceFolder.toFile(), destAppFolder.toFile());
1559 Path filePath = Paths.get(destBaseFolder,
"open.bat");
1562 String casePath =
"..\\" +
caseName;
1563 try (FileWriter writer =
new FileWriter(filePath.toFile())) {
1564 writer.write(exePath +
" \"" + casePath +
"\"");
1603 private class StoreMaxIdCallback
implements CaseDbAccessManager.CaseDbAccessQueryCallback {
1617 Long maxId = rs.getLong(
"max_id");
1618 String query =
" (table_name, max_id) VALUES ('" +
tableName +
"', '" + maxId +
"')";
1621 }
catch (SQLException ex) {
1622 logger.log(Level.WARNING,
"Unable to get maximum ID from result set", ex);
1623 }
catch (TskCoreException ex) {
1624 logger.log(Level.WARNING,
"Unable to save maximum ID from result set", ex);
1628 }
catch (SQLException ex) {
1629 logger.log(Level.WARNING,
"Failed to get maximum ID from result set", ex);
1634 @NbBundle.Messages({
1635 "PortableCaseReportModule.compressCase.errorFinding7zip=Could not locate 7-Zip executable",
1636 "# {0} - Temp folder path",
1637 "PortableCaseReportModule.compressCase.errorCreatingTempFolder=Could not create temporary folder {0}",
1638 "PortableCaseReportModule.compressCase.errorCompressingCase=Error compressing case",
1639 "PortableCaseReportModule.compressCase.canceled=Compression canceled by user",})
1645 Path dirToCompress = Paths.get(folderToCompress);
1646 File tempZipFolder = Paths.get(dirToCompress.getParent().toString(),
"temp",
"portableCase" + System.currentTimeMillis()).toFile();
1647 if (!tempZipFolder.mkdirs()) {
1648 handleError(
"Error creating temporary folder " + tempZipFolder.toString(),
1649 Bundle.PortableCaseReportModule_compressCase_errorCreatingTempFolder(tempZipFolder.toString()),
null, progressPanel);
1655 if (sevenZipExe ==
null) {
1656 handleError(
"Error finding 7-Zip exectuable", Bundle.PortableCaseReportModule_compressCase_errorFinding7zip(),
null, progressPanel);
1661 String chunkOption =
"";
1663 chunkOption =
"-v" +
settings.getChunkSize().getSevenZipParam();
1666 File zipFile = Paths.get(tempZipFolder.getAbsolutePath(),
caseName +
".zip").toFile();
1667 ProcessBuilder procBuilder =
new ProcessBuilder();
1668 procBuilder.command(
1669 sevenZipExe.getAbsolutePath(),
1671 zipFile.getAbsolutePath(),
1672 dirToCompress.toAbsolutePath().toString(),
1677 Process process = procBuilder.start();
1679 while (process.isAlive()) {
1686 int exitCode = process.exitValue();
1687 if (exitCode != 0) {
1689 StringBuilder sb =
new StringBuilder();
1690 try (BufferedReader br =
new BufferedReader(
new InputStreamReader(process.getErrorStream()))) {
1692 while ((line = br.readLine()) !=
null) {
1693 sb.append(line).append(System.getProperty(
"line.separator"));
1697 handleError(
"Error compressing case\n7-Zip output: " + sb.toString(), Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(),
null, progressPanel);
1700 }
catch (IOException | InterruptedException ex) {
1701 handleError(
"Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel);
1707 FileUtils.cleanDirectory(dirToCompress.toFile());
1708 FileUtils.copyDirectory(tempZipFolder, dirToCompress.toFile());
1709 FileUtils.deleteDirectory(
new File(tempZipFolder.getParent()));
1710 }
catch (IOException ex) {
1711 handleError(
"Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel);
1728 String executableToFindName = Paths.get(
"7-Zip",
"7z.exe").toString();
1729 File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName,
PortableCaseReportModule.class.getPackage().getName(),
false);
1730 if (
null == exeFile) {
1734 if (!exeFile.canExecute()) {
1747 private final Map<String, Long>
setCounts =
new HashMap<>();
1754 Long setCount = rs.getLong(
"set_count");
1755 String setName = rs.getString(
"set_name");
1759 }
catch (SQLException ex) {
1760 logger.log(Level.WARNING,
"Unable to get data_source_obj_id or value from result set", ex);
1763 }
catch (SQLException ex) {
1764 logger.log(Level.WARNING,
"Failed to get next result for values by datasource", ex);
SleuthkitCase getSleuthkitCase()
static Case getCurrentCaseThrows()
TagsManager getTagsManager()
static final String TABLE_SCHEMA_SQLITE
static final String TABLE_NAME
static String getAppName()
static String escapeFileName(String fileName)
synchronized static Logger getLogger(String name)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
void updateStatusLabel(String statusMessage)
void complete(ReportStatus reportStatus)
void setIndeterminate(boolean indeterminate)
void process(ResultSet rs)
static final Logger logger
void process(ResultSet rs)
final Map< String, Long > setCounts
static final java.util.logging.Logger logger
Map< String, Long > getSetCountMap()
void process(ResultSet rs)
PortableCaseReportModule()
final Map< TagName, TagName > oldTagNameToNewTagName
final Map< Long, Content > oldIdToNewContent
BlackboardArtifact copyArtifact(long newContentId, BlackboardArtifact artifactToCopy)
Path getApplicationBasePath()
List< String > getAllInterestingItemsSets()
static File locate7ZipExecutable()
static final Logger logger
Multimap< Long, BlackboardArtifact > getInterestingArtifactsBySetName(SleuthkitCase skCase, List< String > setNames)
long copyContent(Content content)
String getExportSubfolder(AbstractFile abstractFile)
void generateCaseUcoReport(List< TagName > tagNames, List< String > setNames, ReportProgressPanel progressPanel)
final Map< Long, OsAccountRealm > oldRealmIdToNewRealm
SleuthkitCase portableSkCase
final Map< Integer, Integer > oldArtTypeIdToNewArtTypeId
boolean compressCase(ReportProgressPanel progressPanel, String folderToCompress)
final Map< Integer, BlackboardAttribute.Type > oldAttrTypeIdToNewAttrType
final Map< Long, BlackboardArtifact > oldArtifactIdToNewArtifact
final Map< Long, OsAccount > oldOsAccountIdToNewOsAccount
static final String FILE_FOLDER_NAME
Host copyHost(Host oldHost)
int getNewArtifactTypeId(BlackboardArtifact oldArtifact)
void createAppLaunchBatFile(String destBaseFolder)
String getAutopsyExeName()
static final List< FileTypeCategory > FILE_TYPE_CATEGORIES
void copyAttachments(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact, AbstractFile newFile)
void closePortableCaseDatabase()
final Map< Long, Content > newIdToContent
static final List< Integer > SPECIALLY_HANDLED_ATTRS
void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel)
void handleCancellation(ReportProgressPanel progressPanel)
void generateReport(String reportPath, PortableCaseReportModuleSettings options, ReportProgressPanel progressPanel)
BlackboardAttribute.Type getNewAttributeType(BlackboardAttribute oldAttribute)
void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)
static final String CASE_UCO_FILE_NAME
String getRelativeFilePath()
final Map< Long, Host > oldHostIdToNewHost
void addImageTagToPortableCase(ContentTag newContentTag, String appData)
String getImageTagDataForContentTag(ContentTag tag)
void copyApplication(Path sourceFolder, String destBaseFolder)
void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)
void initializeImageTags(ReportProgressPanel progressPanel)
static final String CASE_UCO_TMP_DIR
OsAccount copyOsAccount(Long oldOsAccountId)
void copyPathID(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact)
boolean addUniqueFile(Content content, DataSource dataSource, Path tmpDir, Gson gson, CaseUcoExporter exporter, JsonWriter reportWriter, boolean dataSourceHasBeenIncluded)
static final String UNKNOWN_FILE_TYPE_FOLDER
static final String MAX_ID_TABLE_NAME
PortableCaseReportModuleSettings settings
void createCase(File outputDir, ReportProgressPanel progressPanel)
long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel)
boolean includeApplication()
List< String > getSelectedSetNames()
List< TagName > getSelectedTagNames()
boolean areAllSetsSelected()
boolean areAllTagsSelected()