Add tagged images table to html report.

This commit is contained in:
Jeff Wallace 2013-12-20 12:55:10 -05:00
parent 8b203babd8
commit b5a07ed05d
2 changed files with 139 additions and 5 deletions

View File

@ -345,6 +345,8 @@ public class ReportGenerator {
private List<ARTIFACT_TYPE> artifactTypes = new ArrayList<>(); private List<ARTIFACT_TYPE> artifactTypes = new ArrayList<>();
private HashSet<String> tagNamesFilter = new HashSet<>(); private HashSet<String> tagNamesFilter = new HashSet<>();
private List<Content> images = new ArrayList<>();
TableReportsWorker(Map<ARTIFACT_TYPE, Boolean> artifactTypeSelections, Map<String, Boolean> tagNameSelections) { TableReportsWorker(Map<ARTIFACT_TYPE, Boolean> artifactTypeSelections, Map<String, Boolean> tagNameSelections) {
// Get the report modules selected by the user. // Get the report modules selected by the user.
for (Entry<TableReportModule, ReportProgressPanel> entry : tableProgress.entrySet()) { for (Entry<TableReportModule, ReportProgressPanel> entry : tableProgress.entrySet()) {
@ -384,6 +386,7 @@ public class ReportGenerator {
makeBlackboardArtifactTables(); makeBlackboardArtifactTables();
makeContentTagsTables(); makeContentTagsTables();
makeBlackboardArtifactTagsTables(); makeBlackboardArtifactTagsTables();
makeThumbnailTable();
for (TableReportModule module : tableModules) { for (TableReportModule module : tableModules) {
tableProgress.get(module).complete(); tableProgress.get(module).complete();
@ -521,6 +524,7 @@ public class ReportGenerator {
// Give the modules the rows for the content tags. // Give the modules the rows for the content tags.
for (ContentTag tag : tags) { for (ContentTag tag : tags) {
if (passesTagNamesFilter(tag.getName().getDisplayName())) { if (passesTagNamesFilter(tag.getName().getDisplayName())) {
checkIfTagHasImage(tag);
ArrayList<String> rowData = new ArrayList<>(Arrays.asList(tag.getContent().getName(), tag.getName().getDisplayName(), tag.getComment())); ArrayList<String> rowData = new ArrayList<>(Arrays.asList(tag.getContent().getName(), tag.getName().getDisplayName(), tag.getComment()));
for (TableReportModule module : tableModules) { for (TableReportModule module : tableModules) {
// @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink.
@ -581,8 +585,8 @@ public class ReportGenerator {
// Give the modules the rows for the content tags. // Give the modules the rows for the content tags.
for (BlackboardArtifactTag tag : tags) { for (BlackboardArtifactTag tag : tags) {
if (passesTagNamesFilter(tag.getName().getDisplayName())) { if (passesTagNamesFilter(tag.getName().getDisplayName())) {
checkIfTagHasImage(tag);
List<String> row; List<String> row;
File thumbFile;
for (TableReportModule module : tableModules) { for (TableReportModule module : tableModules) {
// We have specific behavior if the module is a ReportHTML. // We have specific behavior if the module is a ReportHTML.
// We add a thumbnail if the artifact is associated with an // We add a thumbnail if the artifact is associated with an
@ -618,6 +622,45 @@ public class ReportGenerator {
} }
} }
} }
private void makeThumbnailTable() {
for (TableReportModule module : tableModules) {
if (module instanceof ReportHTML) {
ReportHTML htmlModule = (ReportHTML) module;
htmlModule.startDataType("Tagged Images", "Tagged Results and Contents that contain images.");
List<String> emptyHeaders = new ArrayList<>();
for (int i = 0; i < ReportHTML.THUMBNAIL_COLUMNS; i++) {
emptyHeaders.add("");
}
htmlModule.startTable(emptyHeaders);
htmlModule.addThumbnailRows(images);
htmlModule.endTable();
htmlModule.endDataType();
}
}
}
private void checkIfTagHasImage(BlackboardArtifactTag artifactTag) {
AbstractFile file;
try {
file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(artifactTag.getArtifact().getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error while getting content from a blackboard artifact to report on.", ex);
return;
}
// Only include content for images
if (ImageUtils.thumbnailSupported(file)) {
images.add(file);
}
}
private void checkIfTagHasImage(ContentTag contentTag) {
Content c = contentTag.getContent();
if (ImageUtils.thumbnailSupported(c)) {
images.add(c);
}
}
} }
/// @@@ Should move the methods specific to TableReportsWorker into that scope. /// @@@ Should move the methods specific to TableReportsWorker into that scope.

View File

@ -34,6 +34,7 @@ import java.io.UnsupportedEncodingException;
import java.io.Writer; import java.io.Writer;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -53,6 +54,7 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
@ -62,6 +64,7 @@ public class ReportHTML implements TableReportModule {
private static ReportHTML instance; private static ReportHTML instance;
private Case currentCase; private Case currentCase;
private SleuthkitCase skCase; private SleuthkitCase skCase;
static Integer THUMBNAIL_COLUMNS = 5;
private Map<String, Integer> dataTypes; private Map<String, Integer> dataTypes;
private String path; private String path;
@ -635,6 +638,94 @@ public class ReportHTML implements TableReportModule {
} }
} }
public void addThumbnailRows(List<Content> images) {
List<String> currentRow = new ArrayList<>();
int totalCount = 0;
for (Content content : images) {
if (currentRow.size() == THUMBNAIL_COLUMNS) {
addRow(currentRow);
currentRow.clear();
}
if (failsContentCheck(content)) {
continue;
}
AbstractFile file = (AbstractFile) content;
String thumbnailPath = saveContent(file);
StringBuilder linkToThumbnail = new StringBuilder();
linkToThumbnail.append("<a href=\"file:///");
linkToThumbnail.append(thumbnailPath);
linkToThumbnail.append("\">");
linkToThumbnail.append("<img src=\"").append(prepareThumbnail(file)).append("\" />");
linkToThumbnail.append("</a>");
currentRow.add(linkToThumbnail.toString());
totalCount++;
}
if (currentRow.isEmpty() == false) {
int extraCells = THUMBNAIL_COLUMNS - currentRow.size();
for (int i = 0; i < extraCells; i++) {
// Finish out the row.
currentRow.add("");
}
addRow(currentRow);
}
// manually set rowCount to be the total number of images.
rowCount = totalCount;
}
private boolean failsContentCheck(Content c) {
if (c instanceof AbstractFile == false) {
return true;
}
AbstractFile file = (AbstractFile) c;
if (file.isDir() ||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS ||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) {
return true;
}
return false;
}
public String saveContent(AbstractFile file) {
// Make a folder for the local file with the same tagName as the tag.
StringBuilder localFilePath = new StringBuilder();
localFilePath.append(path);
localFilePath.append("tagged_images");
File localFileFolder = new File(localFilePath.toString());
if (!localFileFolder.exists()) {
localFileFolder.mkdirs();
}
// Construct a file tagName for the local file that incorporates the file id to ensure uniqueness.
String fileName = file.getName();
String objectIdSuffix = "_" + file.getId();
int lastDotIndex = fileName.lastIndexOf(".");
if (lastDotIndex != -1 && lastDotIndex != 0) {
// The file tagName has a conventional extension. Insert the object id before the '.' of the extension.
fileName = fileName.substring(0, lastDotIndex) + objectIdSuffix + fileName.substring(lastDotIndex, fileName.length());
}
else {
// The file has no extension or the only '.' in the file is an initial '.', as in a hidden file.
// Add the object id to the end of the file tagName.
fileName += objectIdSuffix;
}
localFilePath.append(File.separator);
localFilePath.append(fileName);
// If the local file doesn't already exist, create it now.
// The existence check is necessary because it is possible to apply multiple tags with the same tagName to a file.
File localFile = new File(localFilePath.toString());
if (!localFile.exists()) {
ExtractFscContentVisitor.extract(file, localFile, null, null);
}
return localFilePath.toString();
}
/** /**
* Return a String date for the long date given. * Return a String date for the long date given.
* @param date date as a long * @param date date as a long
@ -949,12 +1040,12 @@ public class ReportHTML implements TableReportModule {
} }
private String prepareThumbnail(AbstractFile file) { private String prepareThumbnail(AbstractFile file) {
File thumbFile = ImageUtils.getIconFile(file, ImageUtils.ICON_SIZE_SMALL); File thumbFile = ImageUtils.getIconFile(file, ImageUtils.ICON_SIZE_MEDIUM);
try { try {
File to = new File(thumbsPath); File to = new File(thumbsPath);
FileUtil.copyFile(FileUtil.toFileObject(thumbFile), FileUtil.toFileObject(to), thumbFile.getName(), ""); FileUtil.copyFile(FileUtil.toFileObject(thumbFile), FileUtil.toFileObject(to), thumbFile.getName(), "");
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to write thumb file to report directory."); logger.log(Level.SEVERE, "Failed to write thumb file to report directory.", ex);
} }
return THUMBS_REL_PATH + thumbFile.getName(); return THUMBS_REL_PATH + thumbFile.getName();