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