/* * Autopsy Forensic Browser * * Copyright 2013-16 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sleuthkit.autopsy.report; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimaps; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.Type; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; class TableReportGenerator { private final List<BlackboardArtifact.Type> artifactTypes = new ArrayList<>(); private final HashSet<String> tagNamesFilter = new HashSet<>(); private final List<Content> images = new ArrayList<>(); private final ReportProgressPanel progressPanel; private final TableReportModule tableReport; private final Map<Integer, List<Column>> columnHeaderMap; private static final Logger logger = Logger.getLogger(TableReportGenerator.class.getName()); private final List<String> errorList; TableReportGenerator(Map<BlackboardArtifact.Type, Boolean> artifactTypeSelections, Map<String, Boolean> tagNameSelections, ReportProgressPanel progressPanel, TableReportModule tableReport) { this.progressPanel = progressPanel; this.tableReport = tableReport; this.columnHeaderMap = new HashMap<>(); errorList = new ArrayList<>(); // Get the artifact types selected by the user. for (Map.Entry<BlackboardArtifact.Type, Boolean> entry : artifactTypeSelections.entrySet()) { if (entry.getValue()) { artifactTypes.add(entry.getKey()); } } // Get the tag names selected by the user and make a tag names filter. if (null != tagNameSelections) { for (Map.Entry<String, Boolean> entry : tagNameSelections.entrySet()) { if (entry.getValue() == true) { tagNamesFilter.add(entry.getKey()); } } } } protected void execute() { // Start the progress indicators for each active TableReportModule. progressPanel.start(); progressPanel.setIndeterminate(false); progressPanel.setMaximumProgress(this.artifactTypes.size() + 2); // +2 for content and blackboard artifact tags // report on the blackboard results if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { makeBlackboardArtifactTables(); } // report on the tagged files and artifacts if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { makeContentTagsTables(); } if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { makeBlackboardArtifactTagsTables(); } if (progressPanel.getStatus() != ReportProgressPanel.ReportStatus.CANCELED) { // report on the tagged images makeThumbnailTable(); } } /** * Generate the tables for the selected blackboard artifacts */ private void makeBlackboardArtifactTables() { // Make a comment string describing the tag names filter in effect. String comment = ""; if (!tagNamesFilter.isEmpty()) { comment += NbBundle.getMessage(this.getClass(), "ReportGenerator.artifactTable.taggedResults.text"); comment += makeCommaSeparatedList(tagNamesFilter); } // Add a table to the report for every enabled blackboard artifact type. for (BlackboardArtifact.Type type : artifactTypes) { // Check for cancellaton. if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { return; } progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", type.getDisplayName())); // Keyword hits and hashset hit artifacts get special handling. if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { writeKeywordHits(tableReport, comment, tagNamesFilter); continue; } else if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { writeHashsetHits(tableReport, comment, tagNamesFilter); continue; } List<ArtifactData> artifactList = getFilteredArtifacts(type, tagNamesFilter); if (artifactList.isEmpty()) { continue; } /* TSK_ACCOUNT artifacts get grouped by their TSK_ACCOUNT_TYPE * attribute, and then handed off to the standard method for writing * tables. */ if (type.getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { //Group account artifacts by their account type ListMultimap<String, ArtifactData> groupedArtifacts = Multimaps.index(artifactList, artifactData -> { try { return artifactData.getArtifact().getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)).getValueString(); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Unable to get value of TSK_ACCOUNT_TYPE attribute. Defaulting to \"unknown\"", ex); return "unknown"; } }); for (String accountType : groupedArtifacts.keySet()) { /* If the report is a ReportHTML, the data type name * eventualy makes it to useDataTypeIcon which expects but * does not require a artifact name, so we make a synthetic * compund name by appending a ":" and the account type. */ final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountType; writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountType)), type, compundDataTypeName, comment); } } else { //all other artifact types are sent to writeTableForDataType directly writeTableForDataType(artifactList, type, type.getDisplayName(), comment); } } } /** * * Write the given list of artifacts to the table for the given type. * * @param artifactList The List of artifacts to include in the table. * @param type The Type of artifacts included in the table. All the * artifacts in artifactList should be of this type. * @param tableName The name of the table. * @param comment A comment to put in the header. */ private void writeTableForDataType(List<ArtifactData> artifactList, BlackboardArtifact.Type type, String tableName, String comment) { /* * Make a sorted set of all of the attribute types that are on any of * the given artifacts. */ Set<BlackboardAttribute.Type> attrTypeSet = new TreeSet<>(Comparator.comparing(BlackboardAttribute.Type::getDisplayName)); for (ArtifactData data : artifactList) { List<BlackboardAttribute> attributes = data.getAttributes(); for (BlackboardAttribute attribute : attributes) { attrTypeSet.add(attribute.getAttributeType()); } } /* Get the columns appropriate for the artifact type. This is used to * get the data that will be in the cells below based on type, and * display the column headers. */ List<Column> columns = getArtifactTableColumns(type.getTypeID(), attrTypeSet); if (columns.isEmpty()) { return; } columnHeaderMap.put(type.getTypeID(), columns); /* The artifact list is sorted now, as getting the row data is dependent * on having the columns, which is necessary for sorting. */ Collections.sort(artifactList); tableReport.startDataType(tableName, comment); tableReport.startTable(Lists.transform(columns, Column::getColumnHeader)); for (ArtifactData artifactData : artifactList) { // Get the row data for this artifact, and has the // module add it. List<String> rowData = artifactData.getRow(); if (rowData.isEmpty()) { return; } tableReport.addRow(rowData); } // Finish up this data type progressPanel.increment(); tableReport.endTable(); tableReport.endDataType(); } /** * Make table for tagged files */ @SuppressWarnings("deprecation") private void makeContentTagsTables() { // Get the content tags. List<ContentTag> tags; try { tags = Case.getCurrentCase().getServices().getTagsManager().getAllContentTags(); } catch (TskCoreException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); logger.log(Level.SEVERE, "failed to get content tags", ex); //NON-NLS return; } // Tell the modules reporting on content tags is beginning. // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName())); ArrayList<String> columnHeaders = new ArrayList<>(Arrays.asList( NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.tag"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.file"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.comment"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeModified"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeChanged"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeAccessed"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.timeCreated"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.size"), NbBundle.getMessage(this.getClass(), "ReportGenerator.htmlOutput.header.hash"))); StringBuilder comment = new StringBuilder(); if (!tagNamesFilter.isEmpty()) { comment.append( NbBundle.getMessage(this.getClass(), "ReportGenerator.makeContTagTab.taggedFiles.msg")); comment.append(makeCommaSeparatedList(tagNamesFilter)); } if (tableReport instanceof ReportHTML) { ReportHTML htmlReportModule = (ReportHTML) tableReport; htmlReportModule.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); htmlReportModule.startContentTagsTable(columnHeaders); } else { tableReport.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); tableReport.startTable(columnHeaders); } // Give the modules the rows for the content tags. for (ContentTag tag : tags) { // skip tags that we are not reporting on if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { continue; } String fileName; try { fileName = tag.getContent().getUniquePath(); } catch (TskCoreException ex) { fileName = tag.getContent().getName(); } ArrayList<String> rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName(), fileName, tag.getComment())); Content content = tag.getContent(); if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile) content; // Add metadata about the file to HTML output rowData.add(file.getMtimeAsDate()); rowData.add(file.getCtimeAsDate()); rowData.add(file.getAtimeAsDate()); rowData.add(file.getCrtimeAsDate()); rowData.add(Long.toString(file.getSize())); rowData.add(file.getMd5Hash()); } // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. if (tableReport instanceof ReportHTML) { ReportHTML htmlReportModule = (ReportHTML) tableReport; htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); } else { tableReport.addRow(rowData); } // see if it is for an image so that we later report on it checkIfTagHasImage(tag); } // The the modules content tags reporting is ended. progressPanel.increment(); tableReport.endTable(); tableReport.endDataType(); } /** * Generate the tables for the tagged artifacts */ @SuppressWarnings("deprecation") private void makeBlackboardArtifactTagsTables() { List<BlackboardArtifactTag> tags; try { tags = Case.getCurrentCase().getServices().getTagsManager().getAllBlackboardArtifactTags(); } catch (TskCoreException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifactTags")); logger.log(Level.SEVERE, "failed to get blackboard artifact tags", ex); //NON-NLS return; } // Tell the modules reporting on blackboard artifact tags data type is beginning. // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName())); StringBuilder comment = new StringBuilder(); if (!tagNamesFilter.isEmpty()) { comment.append( NbBundle.getMessage(this.getClass(), "ReportGenerator.makeBbArtTagTab.taggedRes.msg")); comment.append(makeCommaSeparatedList(tagNamesFilter)); } tableReport.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); tableReport.startTable(new ArrayList<>(Arrays.asList( NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.resultType"), NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.tag"), NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.comment"), NbBundle.getMessage(this.getClass(), "ReportGenerator.tagTable.header.srcFile")))); // Give the modules the rows for the content tags. for (BlackboardArtifactTag tag : tags) { if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) { continue; } List<String> row; row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName())); tableReport.addRow(row); // check if the tag is an image that we should later make a thumbnail for checkIfTagHasImage(tag); } // The the modules blackboard artifact tags reporting is ended. progressPanel.increment(); tableReport.endTable(); tableReport.endDataType(); } /** * Test if the user requested that this tag be reported on * * @param tagName * * @return true if it should be reported on */ private boolean passesTagNamesFilter(String tagName) { return tagNamesFilter.isEmpty() || tagNamesFilter.contains(tagName); } /** * Make a report for the files that were previously found to be images. */ private void makeThumbnailTable() { progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.createdThumb.text")); if (tableReport instanceof ReportHTML) { ReportHTML htmlModule = (ReportHTML) tableReport; htmlModule.startDataType( NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.name"), NbBundle.getMessage(this.getClass(), "ReportGenerator.thumbnailTable.desc")); 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(); } } /** * Analyze artifact associated with tag and add to internal list if it is * associated with an image. * * @param artifactTag */ private void checkIfTagHasImage(BlackboardArtifactTag artifactTag) { AbstractFile file; try { file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(artifactTag.getArtifact().getObjectID()); } catch (TskCoreException ex) { errorList.add( NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.errGetContentFromBBArtifact")); logger.log(Level.WARNING, "Error while getting content from a blackboard artifact to report on.", ex); //NON-NLS return; } if (file != null) { checkIfFileIsImage(file); } } /** * Analyze file that tag is associated with and determine if it is an image * and should have a thumbnail reported for it. Images are added to internal * list. * * @param contentTag */ private void checkIfTagHasImage(ContentTag contentTag) { Content c = contentTag.getContent(); if (c instanceof AbstractFile == false) { return; } checkIfFileIsImage((AbstractFile) c); } /** * If file is an image file, add it to the internal 'images' list. * * @param file */ private void checkIfFileIsImage(AbstractFile file) { if (file.isDir() || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { return; } if (ImageUtils.thumbnailSupported(file)) { images.add(file); } } /** * Converts a collection of strings into a single string of comma-separated * items * * @param items A collection of strings * * @return A string of comma-separated items */ private String makeCommaSeparatedList(Collection<String> items) { String list = ""; for (Iterator<String> iterator = items.iterator(); iterator.hasNext();) { list += iterator.next() + (iterator.hasNext() ? ", " : ""); } return list; } /** * Write the keyword hits to the provided TableReportModules. * * @param tableModule module to report on */ @SuppressWarnings("deprecation") private void writeKeywordHits(TableReportModule tableModule, String comment, HashSet<String> tagNamesFilter) { // Query for keyword lists-only so that we can tell modules what lists // will exist for their index. // @@@ There is a bug in here. We should use the tags in the below code // so that we only report the lists that we will later provide with real // hits. If no keyord hits are tagged, then we make the page for nothing. String orderByClause; if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS } else { orderByClause = "ORDER BY list ASC"; //NON-NLS } String keywordListQuery = "SELECT att.value_text AS list " + //NON-NLS "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + //NON-NLS "WHERE att.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + //NON-NLS "AND art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + " " + //NON-NLS "AND att.artifact_id = art.artifact_id " + //NON-NLS "GROUP BY list " + orderByClause; //NON-NLS try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(keywordListQuery)) { ResultSet listsRs = dbQuery.getResultSet(); List<String> lists = new ArrayList<>(); while (listsRs.next()) { String list = listsRs.getString("list"); //NON-NLS if (list.isEmpty()) { list = NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs"); } lists.add(list); } // Make keyword data type and give them set index tableModule.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); tableModule.addSetIndex(lists); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName())); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryKWLists")); logger.log(Level.SEVERE, "Failed to query keyword lists: ", ex); //NON-NLS return; } if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att3.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(att1.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(att2.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS } else { orderByClause = "ORDER BY list ASC, keyword ASC, parent_path ASC, name ASC, preview ASC"; //NON-NLS } // Query for keywords, grouped by list String keywordsQuery = "SELECT art.artifact_id, art.obj_id, att1.value_text AS keyword, att2.value_text AS preview, att3.value_text AS list, f.name AS name, f.parent_path AS parent_path " + //NON-NLS "FROM blackboard_artifacts AS art, blackboard_attributes AS att1, blackboard_attributes AS att2, blackboard_attributes AS att3, tsk_files AS f " + //NON-NLS "WHERE (att1.artifact_id = art.artifact_id) " + //NON-NLS "AND (att2.artifact_id = art.artifact_id) " + //NON-NLS "AND (att3.artifact_id = art.artifact_id) " + //NON-NLS "AND (f.obj_id = art.obj_id) " + //NON-NLS "AND (att1.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID() + ") " + //NON-NLS "AND (att2.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID() + ") " + //NON-NLS "AND (att3.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + //NON-NLS "AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() + ") " + //NON-NLS orderByClause; //NON-NLS try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(keywordsQuery)) { ResultSet resultSet = dbQuery.getResultSet(); String currentKeyword = ""; String currentList = ""; while (resultSet.next()) { // Check to see if all the TableReportModules have been canceled if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { break; } // Get any tags that associated with this artifact and apply the tag filter. HashSet<String> uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { continue; } String tagsList = makeCommaSeparatedList(uniqueTagNames); Long objId = resultSet.getLong("obj_id"); //NON-NLS String keyword = resultSet.getString("keyword"); //NON-NLS String preview = resultSet.getString("preview"); //NON-NLS String list = resultSet.getString("list"); //NON-NLS String uniquePath = ""; try { AbstractFile f = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId); if (f != null) { uniquePath = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); } } catch (TskCoreException ex) { errorList.add( NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS } // If the lists aren't the same, we've started a new list if ((!list.equals(currentList) && !list.isEmpty()) || (list.isEmpty() && !currentList.equals( NbBundle.getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs")))) { if (!currentList.isEmpty()) { tableModule.endTable(); tableModule.endSet(); } currentList = list.isEmpty() ? NbBundle .getMessage(this.getClass(), "ReportGenerator.writeKwHits.userSrchs") : list; currentKeyword = ""; // reset the current keyword because it's a new list tableModule.startSet(currentList); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); } if (!keyword.equals(currentKeyword)) { if (!currentKeyword.equals("")) { tableModule.endTable(); } currentKeyword = keyword; tableModule.addSetElement(currentKeyword); List<String> columnHeaderNames = new ArrayList<>(); columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview")); columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile")); columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); tableModule.startTable(columnHeaderNames); } String previewreplace = EscapeUtil.escapeHtml(preview); tableModule.addRow(Arrays.asList(new String[]{previewreplace.replaceAll("<!", ""), uniquePath, tagsList})); } // Finish the current data type progressPanel.increment(); tableModule.endDataType(); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryKWs")); logger.log(Level.SEVERE, "Failed to query keywords: ", ex); //NON-NLS } } /** * Write the hash set hits to the provided TableReportModules. * * @param tableModule module to report on */ @SuppressWarnings("deprecation") private void writeHashsetHits(TableReportModule tableModule, String comment, HashSet<String> tagNamesFilter) { String orderByClause; if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST"; //NON-NLS } else { orderByClause = "ORDER BY att.value_text ASC"; //NON-NLS } String hashsetsQuery = "SELECT att.value_text AS list " + //NON-NLS "FROM blackboard_attributes AS att, blackboard_artifacts AS art " + //NON-NLS "WHERE att.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + " " + //NON-NLS "AND art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + " " + //NON-NLS "AND att.artifact_id = art.artifact_id " + //NON-NLS "GROUP BY list " + orderByClause; //NON-NLS try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(hashsetsQuery)) { // Query for hashsets ResultSet listsRs = dbQuery.getResultSet(); List<String> lists = new ArrayList<>(); while (listsRs.next()) { lists.add(listsRs.getString("list")); //NON-NLS } tableModule.startDataType(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); tableModule.addSetIndex(lists); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processing", BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName())); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetLists")); logger.log(Level.SEVERE, "Failed to query hashset lists: ", ex); //NON-NLS return; } if (Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) { orderByClause = "ORDER BY convert_to(att.value_text, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(f.parent_path, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "convert_to(f.name, 'SQL_ASCII') ASC NULLS FIRST, " //NON-NLS + "size ASC NULLS FIRST"; //NON-NLS } else { orderByClause = "ORDER BY att.value_text ASC, f.parent_path ASC, f.name ASC, size ASC"; //NON-NLS } String hashsetHitsQuery = "SELECT art.artifact_id, art.obj_id, att.value_text AS setname, f.name AS name, f.size AS size, f.parent_path AS parent_path " + //NON-NLS "FROM blackboard_artifacts AS art, blackboard_attributes AS att, tsk_files AS f " + //NON-NLS "WHERE (att.artifact_id = art.artifact_id) " + //NON-NLS "AND (f.obj_id = art.obj_id) " + //NON-NLS "AND (att.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + ") " + //NON-NLS "AND (art.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() + ") " + //NON-NLS orderByClause; //NON-NLS try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(hashsetHitsQuery)) { // Query for hashset hits ResultSet resultSet = dbQuery.getResultSet(); String currentSet = ""; while (resultSet.next()) { // Check to see if all the TableReportModules have been canceled if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { break; } // Get any tags that associated with this artifact and apply the tag filter. HashSet<String> uniqueTagNames = getUniqueTagNames(resultSet.getLong("artifact_id")); //NON-NLS if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { continue; } String tagsList = makeCommaSeparatedList(uniqueTagNames); Long objId = resultSet.getLong("obj_id"); //NON-NLS String set = resultSet.getString("setname"); //NON-NLS String size = resultSet.getString("size"); //NON-NLS String uniquePath = ""; try { AbstractFile f = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId); if (f != null) { uniquePath = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(objId).getUniquePath(); } } catch (TskCoreException ex) { errorList.add( NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileFromID")); logger.log(Level.WARNING, "Failed to get Abstract File from ID.", ex); //NON-NLS return; } // If the sets aren't the same, we've started a new set if (!set.equals(currentSet)) { if (!currentSet.isEmpty()) { tableModule.endTable(); tableModule.endSet(); } currentSet = set; tableModule.startSet(currentSet); List<String> columnHeaderNames = new ArrayList<>(); columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file")); columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size")); columnHeaderNames.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags")); tableModule.startTable(columnHeaderNames); progressPanel.updateStatusLabel( NbBundle.getMessage(this.getClass(), "ReportGenerator.progress.processingList", BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), currentSet)); } // Add a row for this hit to every module tableModule.addRow(Arrays.asList(new String[]{uniquePath, size, tagsList})); } // Finish the current data type progressPanel.increment(); tableModule.endDataType(); } catch (TskCoreException | SQLException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedQueryHashsetHits")); logger.log(Level.SEVERE, "Failed to query hashsets hits: ", ex); //NON-NLS } } /** * @return the errorList */ List<String> getErrorList() { return errorList; } /** * Container class that holds data about an Artifact to eliminate duplicate * calls to the Sleuthkit database. */ private class ArtifactData implements Comparable<ArtifactData> { private BlackboardArtifact artifact; private List<BlackboardAttribute> attributes; private HashSet<String> tags; private List<String> rowData = null; private Content content; ArtifactData(BlackboardArtifact artifact, List<BlackboardAttribute> attrs, HashSet<String> tags) { this.artifact = artifact; this.attributes = attrs; this.tags = tags; try { this.content = Case.getCurrentCase().getSleuthkitCase().getContentById(artifact.getObjectID()); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Could not get content from database"); } } public BlackboardArtifact getArtifact() { return artifact; } public List<BlackboardAttribute> getAttributes() { return attributes; } public HashSet<String> getTags() { return tags; } public long getArtifactID() { return artifact.getArtifactID(); } public long getObjectID() { return artifact.getObjectID(); } /** * @return the content */ public Content getContent() { return content; } /** * Compares ArtifactData objects by the first attribute they have in * common in their List<BlackboardAttribute>. Should only be used on two * artifacts of the same type * * If all attributes are the same, they are assumed duplicates and are * compared by their artifact id. Should only be used with attributes of * the same type. */ @Override public int compareTo(ArtifactData otherArtifactData) { List<String> thisRow = getRow(); List<String> otherRow = otherArtifactData.getRow(); for (int i = 0; i < thisRow.size(); i++) { int compare = thisRow.get(i).compareTo(otherRow.get(i)); if (compare != 0) { return compare; } } return ((Long) this.getArtifactID()).compareTo(otherArtifactData.getArtifactID()); } /** * Get the values for each row in the table report. * * the value types of custom artifacts * * @return A list of string representing the data for this artifact. */ public List<String> getRow() { if (rowData == null) { try { rowData = getOrderedRowDataAsStrings(); // If else is done so that row data is not set before // columns are added to the hash map. if (rowData.size() > 0) { // replace null values if attribute was not defined for (int i = 0; i < rowData.size(); i++) { if (rowData.get(i) == null) { rowData.set(i, ""); } } } else { rowData = null; return new ArrayList<>(); } } catch (TskCoreException ex) { errorList.add( NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.coreExceptionWhileGenRptRow")); logger.log(Level.WARNING, "Core exception while generating row data for artifact report.", ex); //NON-NLS rowData = Collections.<String>emptyList(); } } return rowData; } /** * Get a list of Strings with all the row values for the Artifact in the * correct order to be written to the report. * * @return List<String> row values. Values could be null if attribute is * not defined in artifact * * @throws TskCoreException */ private List<String> getOrderedRowDataAsStrings() throws TskCoreException { List<String> orderedRowData = new ArrayList<>(); if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == getArtifact().getArtifactTypeID()) { if (content != null && content instanceof AbstractFile) { AbstractFile file = (AbstractFile) content; orderedRowData.add(file.getName()); orderedRowData.add(file.getNameExtension()); String mimeType = file.getMIMEType(); if (mimeType == null) { orderedRowData.add(""); } else { orderedRowData.add(mimeType); } orderedRowData.add(file.getUniquePath()); } else { // Make empty rows to make sure the formatting is correct orderedRowData.add(null); orderedRowData.add(null); orderedRowData.add(null); orderedRowData.add(null); } orderedRowData.add(makeCommaSeparatedList(getTags())); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == getArtifact().getArtifactTypeID()) { String[] attributeDataArray = new String[3]; // Array is used so that order of the attributes is maintained. for (BlackboardAttribute attr : attributes) { if (attr.getAttributeType().equals(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME))) { attributeDataArray[0] = attr.getDisplayString(); } else if (attr.getAttributeType().equals(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))) { attributeDataArray[1] = attr.getDisplayString(); } } attributeDataArray[2] = content.getUniquePath(); orderedRowData.addAll(Arrays.asList(attributeDataArray)); HashSet<String> allTags = getTags(); try { List<ContentTag> contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content); for (ContentTag ct : contentTags) { allTags.add(ct.getName().getDisplayName()); } } catch (TskCoreException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); logger.log(Level.SEVERE, "Failed to get content tags", ex); //NON-NLS } orderedRowData.add(makeCommaSeparatedList(allTags)); } else if (columnHeaderMap.containsKey(this.artifact.getArtifactTypeID())) { for (Column currColumn : columnHeaderMap.get(this.artifact.getArtifactTypeID())) { String cellData = currColumn.getCellData(this); orderedRowData.add(cellData); } } return orderedRowData; } } /** * Get a List of the artifacts and data of the given type that pass the * given Tag Filter. * * @param type The artifact type to get * @param tagNamesFilter The tag names that should be included. * * @return a list of the filtered tags. */ private List<ArtifactData> getFilteredArtifacts(BlackboardArtifact.Type type, HashSet<String> tagNamesFilter) { List<ArtifactData> artifacts = new ArrayList<>(); try { for (BlackboardArtifact artifact : Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(type.getTypeID())) { List<BlackboardArtifactTag> tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); HashSet<String> uniqueTagNames = new HashSet<>(); for (BlackboardArtifactTag tag : tags) { uniqueTagNames.add(tag.getName().getDisplayName()); } if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { continue; } try { artifacts.add(new ArtifactData(artifact, Case.getCurrentCase().getSleuthkitCase().getBlackboardAttributes(artifact), uniqueTagNames)); } catch (TskCoreException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBAttribs")); logger.log(Level.SEVERE, "Failed to get Blackboard Attributes when generating report.", ex); //NON-NLS } } } catch (TskCoreException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetBBArtifacts")); logger.log(Level.SEVERE, "Failed to get Blackboard Artifacts when generating report.", ex); //NON-NLS } return artifacts; } private Boolean failsTagFilter(HashSet<String> tagNames, HashSet<String> tagsNamesFilter) { if (null == tagsNamesFilter || tagsNamesFilter.isEmpty()) { return false; } HashSet<String> filteredTagNames = new HashSet<>(tagNames); filteredTagNames.retainAll(tagsNamesFilter); return filteredTagNames.isEmpty(); } /** * For a given artifact type ID, return the list of the columns that we are * reporting on. * * @param artifactTypeId artifact type ID * @param attributeTypeSet The set of attributeTypeSet available for this * artifact type * * @return List<String> row titles */ private List<Column> getArtifactTableColumns(int artifactTypeId, Set<BlackboardAttribute.Type> attributeTypeSet) { ArrayList<Column> columns = new ArrayList<>(); // Long switch statement to retain ordering of attribute types that are // attached to pre-defined artifact types. if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateCreated"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.value"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.referrer"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REFERRER))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.title"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.urlDomainDecoded"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL_DECODED))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dest"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.sourceUrl"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.instDateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() == artifactTypeId) { columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.preview"))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() == artifactTypeId) { columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"))); columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.size"))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devMake"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceId"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.domain"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateAccessed"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.progName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTaken"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devManufacturer"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.devModel"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MODEL))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumHome"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumOffice"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumMobile"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.email"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.msgType"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.readStatus"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_READ_STATUS))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromEmail"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toEmail"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.subject"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.text"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.fromPhoneNum"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.toPhoneNum"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.direction"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.calendarEntryType"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CALENDAR_ENTRY_TYPE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.startDateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.endDateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.shortCut"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SHORTCUT))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.phoneNumber"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.deviceAddress"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.altitude"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.locationAddress"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.category"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.password"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PASSWORD))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.personName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.url"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.appPath"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.description"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.replytoAddress"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_REPLYTO))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mailServer"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SERVER_NAME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID() == artifactTypeId) { columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.file"))); columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.extension.text"))); columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.mimeType.text"))); columns.add(new HeaderOnlyColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.path"))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.processorArchitecture.text"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osName.text"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.osInstallDate.text"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailTo"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailFrom"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSubject"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeSent"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskDateTimeRcvd"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_RCVD))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailCc"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_CC))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskEmailBcc"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_BCC))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskMsgId"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskInterestingFilesCategory"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskPath"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskGpsRouteCategory"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeEnd"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeEnd"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.latitudeStart"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.longitudeStart"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.name"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.location"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tskSetName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.program"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.associatedArtifact"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.dateTime"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.count"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COUNT))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userName"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.userId"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID))); } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_REMOTE_DRIVE.getTypeID() == artifactTypeId) { columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.localPath"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCAL_PATH))); columns.add(new AttributeColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.remotePath"), new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REMOTE_PATH))); } else if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { columns.add(new StatusColumn()); attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)); attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID)); } else { // This is the case that it is a custom type. The reason an else is // necessary is to make sure that the source file column is added for (BlackboardAttribute.Type type : attributeTypeSet) { columns.add(new AttributeColumn(type.getDisplayName(), type)); } columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile"))); columns.add(new TaggedResultsColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))); // Short circuits to guarantee that the attribute types aren't added // twice. return columns; } // If it is an attribute column, it removes the attribute type of that // column from the set, so types are not reported more than once. for (Column column : columns) { attributeTypeSet = column.removeTypeFromSet(attributeTypeSet); } // Now uses the remaining types in the set to construct columns for (BlackboardAttribute.Type type : attributeTypeSet) { columns.add(new AttributeColumn(type.getDisplayName(), type)); } // Source file column is added here for ordering purposes. if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALENDAR_ENTRY.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_SPEED_DIAL_ENTRY.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_SEARCH.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() || artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_INFO.getTypeID()) { columns.add(new SourceFileColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.srcFile"))); } columns.add(new TaggedResultsColumn(NbBundle.getMessage(this.getClass(), "ReportGenerator.artTableColHdr.tags"))); return columns; } /** * Given a tsk_file's obj_id, return the unique path of that file. * * @param objId tsk_file obj_id * * @return String unique path */ private String getFileUniquePath(Content content) { try { if (content != null) { return content.getUniquePath(); } else { return ""; } } catch (TskCoreException ex) { errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetAbstractFileByID")); logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); //NON-NLS } return ""; } /** * Get any tags associated with an artifact * * @param artifactId * * @return hash set of tag display names * * @throws SQLException */ @SuppressWarnings("deprecation") private HashSet<String> getUniqueTagNames(long artifactId) throws TskCoreException { HashSet<String> uniqueTagNames = new HashSet<>(); String query = "SELECT display_name, artifact_id FROM tag_names AS tn, blackboard_artifact_tags AS bat " + //NON-NLS "WHERE tn.tag_name_id = bat.tag_name_id AND bat.artifact_id = " + artifactId; //NON-NLS try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(query)) { ResultSet tagNameRows = dbQuery.getResultSet(); while (tagNameRows.next()) { uniqueTagNames.add(tagNameRows.getString("display_name")); //NON-NLS } } catch (TskCoreException | SQLException ex) { throw new TskCoreException("Error getting tag names for artifact: ", ex); } return uniqueTagNames; } private interface Column { String getColumnHeader(); String getCellData(ArtifactData artData); Set<BlackboardAttribute.Type> removeTypeFromSet(Set<BlackboardAttribute.Type> types); } private class StatusColumn implements Column { @NbBundle.Messages("TableReportGenerator.StatusColumn.Header=Review Status") @Override public String getColumnHeader() { return Bundle.TableReportGenerator_StatusColumn_Header(); } @Override public String getCellData(ArtifactData artData) { return artData.getArtifact().getReviewStatus().getDisplayName(); } @Override public Set<BlackboardAttribute.Type> removeTypeFromSet(Set<BlackboardAttribute.Type> types) { // This column doesn't have a type, so nothing to remove return types; } } private class AttributeColumn implements Column { private final String columnHeader; private final BlackboardAttribute.Type attributeType; /** * Constructs an ArtifactCell * * @param columnHeader The header text of this column * @param attributeType The attribute type associated with this column */ AttributeColumn(String columnHeader, BlackboardAttribute.Type attributeType) { this.columnHeader = Objects.requireNonNull(columnHeader); this.attributeType = attributeType; } @Override public String getColumnHeader() { return this.columnHeader; } @Override public String getCellData(ArtifactData artData) { List<BlackboardAttribute> attributes = artData.getAttributes(); for (BlackboardAttribute attribute : attributes) { if (attribute.getAttributeType().equals(this.attributeType)) { if (attribute.getAttributeType().getValueType() != BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { return attribute.getDisplayString(); } else { return ContentUtils.getStringTime(attribute.getValueLong(), artData.getContent()); } } } return ""; } @Override public Set<BlackboardAttribute.Type> removeTypeFromSet(Set<BlackboardAttribute.Type> types) { types.remove(this.attributeType); return types; } } private class SourceFileColumn implements Column { private final String columnHeader; SourceFileColumn(String columnHeader) { this.columnHeader = columnHeader; } @Override public String getColumnHeader() { return this.columnHeader; } @Override public String getCellData(ArtifactData artData) { return getFileUniquePath(artData.getContent()); } @Override public Set<BlackboardAttribute.Type> removeTypeFromSet(Set<BlackboardAttribute.Type> types) { // This column doesn't have a type, so nothing to remove return types; } } private class TaggedResultsColumn implements Column { private final String columnHeader; TaggedResultsColumn(String columnHeader) { this.columnHeader = columnHeader; } @Override public String getColumnHeader() { return this.columnHeader; } @Override public String getCellData(ArtifactData artData) { return makeCommaSeparatedList(artData.getTags()); } @Override public Set<BlackboardAttribute.Type> removeTypeFromSet(Set<BlackboardAttribute.Type> types) { // This column doesn't have a type, so nothing to remove return types; } } private class HeaderOnlyColumn implements Column { private final String columnHeader; HeaderOnlyColumn(String columnHeader) { this.columnHeader = columnHeader; } @Override public String getColumnHeader() { return columnHeader; } @Override public String getCellData(ArtifactData artData) { throw new UnsupportedOperationException("Cannot get cell data of unspecified column"); } @Override public Set<BlackboardAttribute.Type> removeTypeFromSet(Set<BlackboardAttribute.Type> types) { // This column doesn't have a type, so nothing to remove return types; } } }