Merge branch 'develop' of https://github.com/sleuthkit/autopsy into develop

This commit is contained in:
Raman 2018-06-18 15:13:09 -04:00
commit 24dda87c0f
52 changed files with 1529 additions and 364 deletions

View File

@ -84,17 +84,17 @@
<target name="getTestDataFiles"> <target name="getTestDataFiles">
<mkdir dir="${basedir}/test/qa-functional/data"/> <mkdir dir="${basedir}/test/qa-functional/data"/>
<get src="https://drive.google.com/uc?id=1dLYGctuvRQMmnzfXPppTM_9gB49eLc_g" dest="${test-input}/embedded.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1dLYGctuvRQMmnzfXPppTM_9gB49eLc_g" dest="${test-input}/EmbeddedIM_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1JACMDyH4y54ypGzFWl82ZzMQf3qbrioP" dest="${test-input}/encryption_detection_bitlocker_test.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1JACMDyH4y54ypGzFWl82ZzMQf3qbrioP" dest="${test-input}/BitlockerDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=17sGybvmBGsWWJYo1IWKmO04oG9hKpPi3" dest="${test-input}/encryption_detection_sqlcipher_test.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=17sGybvmBGsWWJYo1IWKmO04oG9hKpPi3" dest="${test-input}/SqlCipherDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=0BxdBkzm5VKGNT0dGY0dqcHVsU3M" dest="${test-input}/filter_test1.img" skipexisting="true"/> <get src="https://drive.google.com/uc?id=0BxdBkzm5VKGNT0dGY0dqcHVsU3M" dest="${test-input}/IngestFilters_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1bghoSm7z7nhmGIxlllyY1MMlbLntxm7n" dest="${test-input}/local_files_test.zip" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1bghoSm7z7nhmGIxlllyY1MMlbLntxm7n" dest="${test-input}/IngestFilters_local1_v1.zip" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1BrSiUQ1fzxFS9vIaK4mYKX6qIVp9kRWT" dest="${test-input}/password_detection_test.img" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1BrSiUQ1fzxFS9vIaK4mYKX6qIVp9kRWT" dest="${test-input}/PasswordDetection_img1_v1.img" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1HD8s4rculgHV1qZT5g80Kg7j4m1qccrN" dest="${test-input}/veracrypt_detection_test.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1HD8s4rculgHV1qZT5g80Kg7j4m1qccrN" dest="${test-input}/VeracryptDetection_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1O5D09fFCFpXZqw0uLEs8kVLtfYTxqXAd" dest="${test-input}/commonfiles_image1_v1.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1mr9waEDG5H8GBBn_yXwMUQ6senwC1goL" dest="${test-input}/CommonFiles_img1_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1rMP1QTI0LdppzdypbG-4BDwkKcR3tHXc" dest="${test-input}/commonfiles_image2_v1.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1-vmbmAAb2HBLbf58GpAA97ozGUFiYHbN" dest="${test-input}/CommonFiles_img2_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1OdwyJ2lru55ZPdvwzj3pq6sXIys27i4x" dest="${test-input}/commonfiles_image3_v1.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1ghDjm0NhI3ShMQ38E-4o7XrGeexpjdJb" dest="${test-input}/CommonFiles_img3_v1.vhd" skipexisting="true"/>
<get src="https://drive.google.com/uc?id=1GoF2x0km5AyFvE926ttN20lrMX1oLN7E" dest="${test-input}/commonfiles_image4_v1.vhd" skipexisting="true"/> <get src="https://drive.google.com/uc?id=1SJYJFjiumKEtQmeMPsQ6G3xmABarbKm_" dest="${test-input}/CommonFiles_img4_v1.vhd" skipexisting="true"/>
</target> </target>
<target name="get-deps" depends="init-ivy,getTSKJars,get-thirdparty-dependencies,get-InternalPythonModules, download-binlist,getTestDataFiles"> <target name="get-deps" depends="init-ivy,getTSKJars,get-thirdparty-dependencies,get-InternalPythonModules, download-binlist,getTestDataFiles">

View File

@ -166,6 +166,21 @@ public class TagsManager implements Closeable {
return caseDb.getTagNamesInUse(); return caseDb.getTagNamesInUse();
} }
/**
* Selects all of the rows from the tag_names table in the case database for
* which there is at least one matching row in the content_tags or
* blackboard_artifact_tags tables, for the given data source object id.
*
* @param dsObjId data source object id
*
* @return A list, possibly empty, of TagName data transfer objects (DTOs)
* for the rows.
*
* @throws TskCoreException
*/
public List<TagName> getTagNamesInUse(long dsObjId) throws TskCoreException {
return caseDb.getTagNamesInUse(dsObjId);
}
/** /**
* Gets a map of tag display names to tag name entries in the case database. * Gets a map of tag display names to tag name entries in the case database.
* It has keys for the display names of the standard tag types, the current * It has keys for the display names of the standard tag types, the current
@ -401,6 +416,24 @@ public class TagsManager implements Closeable {
return caseDb.getContentTagsCountByTagName(tagName); return caseDb.getContentTagsCountByTagName(tagName);
} }
/**
* Gets content tags count by tag name, for the given data source
*
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames and/or addTagName.
*
* @param dsObjId data source object id
*
* @return A count of the content tags with the specified tag name, and for
* the given data source
*
* @throws TskCoreException If there is an error getting the tags count from
* the case database.
*/
public long getContentTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
return caseDb.getContentTagsCountByTagName(tagName, dsObjId);
}
/** /**
* Gets a content tag by tag id. * Gets a content tag by tag id.
* *
@ -430,6 +463,23 @@ public class TagsManager implements Closeable {
return caseDb.getContentTagsByTagName(tagName); return caseDb.getContentTagsByTagName(tagName);
} }
/**
* Gets content tags by tag name, for the given data source.
*
* @param tagName The tag name of interest.
*
* @param dsObjId data source object id
*
* @return A list, possibly empty, of the content tags with the specified
* tag name, and for the given data source.
*
* @throws TskCoreException If there is an error getting the tags from the
* case database.
*/
public List<ContentTag> getContentTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
return caseDb.getContentTagsByTagName(tagName, dsObjId);
}
/** /**
* Gets content tags count by content. * Gets content tags count by content.
* *
@ -531,6 +581,24 @@ public class TagsManager implements Closeable {
return caseDb.getBlackboardArtifactTagsCountByTagName(tagName); return caseDb.getBlackboardArtifactTagsCountByTagName(tagName);
} }
/**
* Gets an artifact tags count by tag name, for the given data source.
*
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
* @param dsObjId data source object id
*
* @return A count of the artifact tags with the specified tag name,
* for the given data source.
*
* @throws TskCoreException If there is an error getting the tags count from
* the case database.
*/
public long getBlackboardArtifactTagsCountByTagName(TagName tagName, long dsObjId) throws TskCoreException {
return caseDb.getBlackboardArtifactTagsCountByTagName(tagName, dsObjId);
}
/** /**
* Gets an artifact tag by tag id. * Gets an artifact tag by tag id.
* *
@ -562,6 +630,24 @@ public class TagsManager implements Closeable {
return caseDb.getBlackboardArtifactTagsByTagName(tagName); return caseDb.getBlackboardArtifactTagsByTagName(tagName);
} }
/**
* Gets artifact tags by tag name, for specified data source.
*
* @param tagName The representation of the desired tag type in the case
* database, which can be obtained by calling getTagNames
* and/or addTagName.
* @param dsObjId data source object id
*
* @return A list, possibly empty, of the artifact tags with the specified
* tag name, for the specified data source.
*
* @throws TskCoreException If there is an error getting the tags from the
* case database.
*/
public List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName, long dsObjId) throws TskCoreException {
return caseDb.getBlackboardArtifactTagsByTagName(tagName, dsObjId);
}
/** /**
* Gets artifact tags for a particular artifact. * Gets artifact tags for a particular artifact.
* *

View File

@ -83,8 +83,13 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction {
* comment. The comment will be updated in the database if the file instance * comment. The comment will be updated in the database if the file instance
* exists there, or a new file instance will be added to the database with * exists there, or a new file instance will be added to the database with
* the comment attached otherwise. * the comment attached otherwise.
*
* The current comment for this instance is returned in case it is needed to
* update the display.
*
* @return the current comment for this instance
*/ */
public void addEditCentralRepoComment() { public String addEditCentralRepoComment() {
CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title); CentralRepoCommentDialog centralRepoCommentDialog = new CentralRepoCommentDialog(correlationAttribute, title);
centralRepoCommentDialog.display(); centralRepoCommentDialog.display();
@ -103,6 +108,7 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction {
logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex);
} }
} }
return centralRepoCommentDialog.getComment();
} }
/** /**

View File

@ -31,6 +31,7 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
private final CorrelationAttribute correlationAttribute; private final CorrelationAttribute correlationAttribute;
private boolean commentUpdated = false; private boolean commentUpdated = false;
private String currentComment = "";
/** /**
* Create an instance. * Create an instance.
@ -44,6 +45,11 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
initComponents(); initComponents();
CorrelationAttributeInstance instance = correlationAttribute.getInstances().get(0); CorrelationAttributeInstance instance = correlationAttribute.getInstances().get(0);
// Store the original comment
if (instance.getComment() != null) {
currentComment = instance.getComment();
}
pathLabel.setText(instance.getFilePath()); pathLabel.setText(instance.getFilePath());
commentTextArea.setText(instance.getComment()); commentTextArea.setText(instance.getComment());
@ -71,6 +77,16 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
boolean isCommentUpdated() { boolean isCommentUpdated() {
return commentUpdated; return commentUpdated;
} }
/**
* Get the current comment.
* If the user hit OK, this will be the new comment.
* If the user canceled, this will be the original comment.
* @return the comment
*/
String getComment() {
return currentComment;
}
/** /**
* This method is called from within the constructor to initialize the form. * This method is called from within the constructor to initialize the form.
@ -168,8 +184,8 @@ final class CentralRepoCommentDialog extends javax.swing.JDialog {
}//GEN-LAST:event_cancelButtonActionPerformed }//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
String comment = commentTextArea.getText(); currentComment = commentTextArea.getText();
correlationAttribute.getInstances().get(0).setComment(comment); correlationAttribute.getInstances().get(0).setComment(currentComment);
commentUpdated = true; commentUpdated = true;
dispose(); dispose();

View File

@ -0,0 +1,56 @@
/*
* Central Repository
*
* Copyright 2018 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.centralrepository;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.Action;
import org.openide.util.Utilities;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider;
import org.sleuthkit.datamodel.AbstractFile;
/**
* This creates a single context menu item for adding or editing a Central
* Repository comment.
*/
@ServiceProvider(service = ContextMenuActionsProvider.class)
public class CentralRepoContextMenuActionsProvider implements ContextMenuActionsProvider {
@Override
public List<Action> getActions() {
ArrayList<Action> actions = new ArrayList<>();
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
if (selectedFiles.size() != 1) {
return actions;
}
for (AbstractFile file : selectedFiles) {
if (EamDbUtil.useCentralRepo() && EamArtifactUtil.isSupportedAbstractFileType(file) && file.isFile()) {
actions.add(AddEditCentralRepoCommentAction.createAddEditCentralRepoCommentAction(file));
}
}
return actions;
}
}

View File

@ -56,7 +56,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
@ -69,7 +68,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
/** /**
* View correlation results from other cases * View correlation results from other cases
@ -119,10 +117,15 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} else if (jmi.equals(showCommonalityMenuItem)) { } else if (jmi.equals(showCommonalityMenuItem)) {
showCommonalityDetails(); showCommonalityDetails();
} else if (jmi.equals(addCommentMenuItem)) { } else if (jmi.equals(addCommentMenuItem)) {
CorrelationAttribute selectedAttribute = (CorrelationAttribute) tableModel.getRow(otherCasesTable.getSelectedRow()); try {
AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedAttribute); OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(otherCasesTable.getSelectedRow());
action.addEditCentralRepoComment(); AddEditCentralRepoCommentAction action = AddEditCentralRepoCommentAction.createAddEditCommentAction(selectedNode.createCorrelationAttribute());
otherCasesTable.repaint(); String currentComment = action.addEditCentralRepoComment();
selectedNode.updateComment(currentComment);
otherCasesTable.repaint();
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error performing Add/Edit Comment action", ex);
}
} }
} }
}; };
@ -202,8 +205,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
if (-1 != selectedRowViewIdx) { if (-1 != selectedRowViewIdx) {
EamDb dbManager = EamDb.getInstance(); EamDb dbManager = EamDb.getInstance();
int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx); int selectedRowModelIdx = otherCasesTable.convertRowIndexToModel(selectedRowViewIdx);
CorrelationAttribute eamArtifact = (CorrelationAttribute) tableModel.getRow(selectedRowModelIdx); OtherOccurrenceNodeData nodeData = (OtherOccurrenceNodeData) tableModel.getRow(selectedRowModelIdx);
CorrelationCase eamCasePartial = eamArtifact.getInstances().get(0).getCorrelationCase(); CorrelationCase eamCasePartial = nodeData.getCorrelationAttributeInstance().getCorrelationCase();
if (eamCasePartial == null) { if (eamCasePartial == null) {
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem, JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference(), Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetailsReference(),
@ -454,9 +457,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} }
/** /**
* Query the database for artifact instances from other cases correlated to * Query the central repo database (if enabled) and the case database to find all
* the given central repository artifact. Instances from the same datasource * artifact instances correlated to the given central repository artifact. If the
* / device will also be included. * central repo is not enabled, this will only return files from the current case
* with matching MD5 hashes.
* *
* @param corAttr CorrelationAttribute to query for * @param corAttr CorrelationAttribute to query for
* @param dataSourceName Data source to filter results * @param dataSourceName Data source to filter results
@ -464,33 +468,46 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
* *
* @return A collection of correlated artifact instances * @return A collection of correlated artifact instances
*/ */
private Map<UniquePathKey, CorrelationAttributeInstance> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) { private Map<UniquePathKey,OtherOccurrenceNodeData> getCorrelatedInstances(CorrelationAttribute corAttr, String dataSourceName, String deviceId) {
// @@@ Check exception // @@@ Check exception
try { try {
final Case openCase = Case.getCurrentCase(); final Case openCase = Case.getCurrentCase();
String caseUUID = openCase.getName(); String caseUUID = openCase.getName();
String filePath = (file.getParentPath() + file.getName()).toLowerCase();
HashMap<UniquePathKey, CorrelationAttributeInstance> artifactInstances = new HashMap<>(); HashMap<UniquePathKey,OtherOccurrenceNodeData> nodeDataMap = new HashMap<>();
if (EamDb.isEnabled()) { if (EamDb.isEnabled()) {
EamDb dbManager = EamDb.getInstance(); List<CorrelationAttributeInstance> instances = EamDb.getInstance().getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue());
artifactInstances.putAll(dbManager.getArtifactInstancesByTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).stream()
.filter(artifactInstance -> !artifactInstance.getFilePath().equals(filePath)
|| !artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
|| !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
|| !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId))
.collect(Collectors.toMap(correlationAttr -> new UniquePathKey(correlationAttr.getCorrelationDataSource().getDeviceID(), correlationAttr.getFilePath()),
correlationAttr -> correlationAttr)));
}
if (corAttr.getCorrelationType().getDisplayName().equals("Files")) { for (CorrelationAttributeInstance artifactInstance:instances) {
List<AbstractFile> caseDbFiles = addCaseDbMatches(corAttr, openCase);
for (AbstractFile caseDbFile : caseDbFiles) { // Only add the attribute if it isn't the object the user selected.
addOrUpdateAttributeInstance(openCase, artifactInstances, caseDbFile); // We consider it to be a different object if at least one of the following is true:
// - the case UUID is different
// - the data source name is different
// - the data source device ID is different
// - the file path is different
if (!artifactInstance.getCorrelationCase().getCaseUUID().equals(caseUUID)
|| !artifactInstance.getCorrelationDataSource().getName().equals(dataSourceName)
|| !artifactInstance.getCorrelationDataSource().getDeviceID().equals(deviceId)
|| !artifactInstance.getFilePath().equalsIgnoreCase(file.getParentPath() + file.getName())) {
OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(artifactInstance, corAttr.getCorrelationType(), corAttr.getCorrelationValue());
UniquePathKey uniquePathKey = new UniquePathKey(newNode);
nodeDataMap.put(uniquePathKey, newNode);
}
} }
} }
return artifactInstances; if (corAttr.getCorrelationType().getDisplayName().equals("Files")) {
List<AbstractFile> caseDbFiles = getCaseDbMatches(corAttr, openCase);
for (AbstractFile caseDbFile : caseDbFiles) {
addOrUpdateNodeData(openCase, nodeDataMap, caseDbFile);
}
}
return nodeDataMap;
} catch (EamDbException ex) { } catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS logger.log(Level.SEVERE, "Error getting artifact instances from database.", ex); // NON-NLS
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
@ -504,7 +521,16 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
return new HashMap<>(0); return new HashMap<>(0);
} }
private List<AbstractFile> addCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException { /**
* Get all other abstract files in the current case with the same MD5 as the selected node.
* @param corAttr The CorrelationAttribute containing the MD5 to search for
* @param openCase The current case
* @return List of matching AbstractFile objects
* @throws NoCurrentCaseException
* @throws TskCoreException
* @throws EamDbException
*/
private List<AbstractFile> getCaseDbMatches(CorrelationAttribute corAttr, Case openCase) throws NoCurrentCaseException, TskCoreException, EamDbException {
String md5 = corAttr.getCorrelationValue(); String md5 = corAttr.getCorrelationValue();
SleuthkitCase tsk = openCase.getSleuthkitCase(); SleuthkitCase tsk = openCase.getSleuthkitCase();
@ -522,75 +548,64 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} }
/** /**
* Adds the file to the artifactInstances map if it does not already exist * Adds the file to the nodeDataMap map if it does not already exist
* *
* @param autopsyCase * @param autopsyCase
* @param artifactInstances * @param nodeDataMap
* @param newFile * @param newFile
* *
* @throws TskCoreException * @throws TskCoreException
* @throws EamDbException * @throws EamDbException
*/ */
private void addOrUpdateAttributeInstance(final Case autopsyCase, Map<UniquePathKey, CorrelationAttributeInstance> artifactInstances, AbstractFile newFile) throws TskCoreException, EamDbException { private void addOrUpdateNodeData(final Case autopsyCase, Map<UniquePathKey,OtherOccurrenceNodeData> nodeDataMap, AbstractFile newFile) throws TskCoreException, EamDbException {
// figure out if the casedb file is known via either hash or tags OtherOccurrenceNodeData newNode = new OtherOccurrenceNodeData(newFile, autopsyCase);
TskData.FileKnown localKnown = newFile.getKnown();
// If the caseDB object has a notable tag associated with it, update
if (localKnown != TskData.FileKnown.BAD) { // the known status to BAD
if (newNode.getKnown() != TskData.FileKnown.BAD) {
List<ContentTag> fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile); List<ContentTag> fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile);
for (ContentTag tag : fileMatchTags) { for (ContentTag tag : fileMatchTags) {
TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus(); TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus();
if (tagKnownStatus.equals(TskData.FileKnown.BAD)) { if (tagKnownStatus.equals(TskData.FileKnown.BAD)) {
localKnown = TskData.FileKnown.BAD; newNode.updateKnown(TskData.FileKnown.BAD);
break; break;
} }
} }
} }
// make a key to see if the file is already in the map // Make a key to see if the file is already in the map
String filePath = newFile.getParentPath() + newFile.getName(); UniquePathKey uniquePathKey = new UniquePathKey(newNode);
String deviceId;
try { // If this node is already in the list, the only thing we need to do is
deviceId = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId()).getDeviceId(); // update the known status to BAD if the caseDB version had known status BAD.
} catch (TskDataException | TskCoreException ex) { // Otherwise this is a new node so add the new node to the map.
logger.log(Level.WARNING, "Error getting data source info: {0}", ex); if (nodeDataMap.containsKey(uniquePathKey)) {
return; if (newNode.getKnown() == TskData.FileKnown.BAD) {
} OtherOccurrenceNodeData prevInstance = nodeDataMap.get(uniquePathKey);
UniquePathKey uniquePathKey = new UniquePathKey(deviceId, filePath); prevInstance.updateKnown(newNode.getKnown());
// double check that the CR version is BAD if the caseDB version is BAD.
if (artifactInstances.containsKey(uniquePathKey)) {
if (localKnown == TskData.FileKnown.BAD) {
CorrelationAttributeInstance prevInstance = artifactInstances.get(uniquePathKey);
prevInstance.setKnownStatus(localKnown);
} }
} // add the data from the case DB by pushing data into CorrelationAttributeInstance class } else {
else { nodeDataMap.put(uniquePathKey, newNode);
// NOTE: If we are in here, it is likely because CR is not enabled. So, we cannot rely
// on any of the methods that query the DB.
CorrelationCase correlationCase = new CorrelationCase(autopsyCase.getName(), autopsyCase.getDisplayName());
CorrelationDataSource correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, newFile.getDataSource());
CorrelationAttributeInstance caseDbInstance = new CorrelationAttributeInstance(correlationCase, correlationDataSource, filePath, "", localKnown);
artifactInstances.put(uniquePathKey, caseDbInstance);
} }
} }
@Override @Override
public boolean isSupported(Node node) { public boolean isSupported(Node node) {
this.file = this.getAbstractFileFromNode(node);
// Is supported if this node
// has correlatable content (File, BlackboardArtifact) OR
// other common files across datasources.
// Is supported if one of the following is true:
// - The central repo is enabled and the node has correlatable content
// (either through the MD5 hash of the associated file or through a BlackboardArtifact)
// - The central repo is disabled and the backing file has a valid MD5 hash
this.file = this.getAbstractFileFromNode(node);
if (EamDb.isEnabled()) { if (EamDb.isEnabled()) {
return this.file != null return this.file != null
&& this.file.getSize() > 0 && this.file.getSize() > 0
&& !getCorrelationAttributesFromNode(node).isEmpty(); && !getCorrelationAttributesFromNode(node).isEmpty();
} else { } else {
return this.file != null return this.file != null
&& this.file.getSize() > 0; && this.file.getSize() > 0
&& ((this.file.getMd5Hash() != null) && ( ! this.file.getMd5Hash().isEmpty()));
} }
} }
@ -632,22 +647,14 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// get the attributes we can correlate on // get the attributes we can correlate on
correlationAttributes.addAll(getCorrelationAttributesFromNode(node)); correlationAttributes.addAll(getCorrelationAttributesFromNode(node));
for (CorrelationAttribute corAttr : correlationAttributes) { for (CorrelationAttribute corAttr : correlationAttributes) {
Map<UniquePathKey, CorrelationAttributeInstance> corAttrInstances = new HashMap<>(0); Map<UniquePathKey,OtherOccurrenceNodeData> correlatedNodeDataMap = new HashMap<>(0);
// get correlation and reference set instances from DB // get correlation and reference set instances from DB
corAttrInstances.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); correlatedNodeDataMap.putAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId));
correlatedNodeDataMap.values().forEach((nodeData) -> {
tableModel.addNodeData(nodeData);
corAttrInstances.values().forEach((corAttrInstance) -> {
try {
CorrelationAttribute newCeArtifact = new CorrelationAttribute(
corAttr.getCorrelationType(),
corAttr.getCorrelationValue()
);
newCeArtifact.addInstance(corAttrInstance);
tableModel.addEamArtifact(newCeArtifact);
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error creating correlation attribute", ex);
}
}); });
} }
@ -816,18 +823,19 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible private void rightClickPopupMenuPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
boolean addCommentMenuItemVisible = false; boolean enableCentralRepoActions = false;
if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) { if (EamDbUtil.useCentralRepo() && otherCasesTable.getSelectedRowCount() == 1) {
int rowIndex = otherCasesTable.getSelectedRow(); int rowIndex = otherCasesTable.getSelectedRow();
CorrelationAttribute selectedAttribute = (CorrelationAttribute) tableModel.getRow(rowIndex); OtherOccurrenceNodeData selectedNode = (OtherOccurrenceNodeData) tableModel.getRow(rowIndex);
if (selectedAttribute.getInstances().get(0).isDatabaseInstance() if (selectedNode.isCentralRepoNode()) {
&& selectedAttribute.getCorrelationType().getId() == CorrelationAttribute.FILES_TYPE_ID) { enableCentralRepoActions = true;
addCommentMenuItemVisible = true;
} }
} }
addCommentMenuItem.setVisible(addCommentMenuItemVisible); addCommentMenuItem.setVisible(enableCentralRepoActions);
showCaseDetailsMenuItem.setVisible(enableCentralRepoActions);
showCommonalityMenuItem.setVisible(enableCentralRepoActions);
}//GEN-LAST:event_rightClickPopupMenuPopupMenuWillBecomeVisible }//GEN-LAST:event_rightClickPopupMenuPopupMenuWillBecomeVisible
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
@ -854,33 +862,26 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
private final String dataSourceID; private final String dataSourceID;
private final String filePath; private final String filePath;
private final String type;
UniquePathKey(String theDataSource, String theFilePath) { UniquePathKey(OtherOccurrenceNodeData nodeData) {
super(); super();
dataSourceID = theDataSource; dataSourceID = nodeData.getDeviceID();
filePath = theFilePath.toLowerCase(); if (nodeData.getFilePath() != null) {
} filePath = nodeData.getFilePath().toLowerCase();
} else {
/** filePath = null;
* }
* @return the dataSourceID device ID type = nodeData.getType();
*/
String getDataSourceID() {
return dataSourceID;
}
/**
*
* @return the filPath including the filename and extension.
*/
String getFilePath() {
return filePath;
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (other instanceof UniquePathKey) { if (other instanceof UniquePathKey) {
return ((UniquePathKey) other).getDataSourceID().equals(dataSourceID) && ((UniquePathKey) other).getFilePath().equals(filePath); UniquePathKey otherKey = (UniquePathKey)(other);
return ( Objects.equals(otherKey.dataSourceID, this.dataSourceID)
&& Objects.equals(otherKey.filePath, this.filePath)
&& Objects.equals(otherKey.type, this.type));
} }
return false; return false;
} }
@ -890,7 +891,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
//int hash = 7; //int hash = 7;
//hash = 67 * hash + this.dataSourceID.hashCode(); //hash = 67 * hash + this.dataSourceID.hashCode();
//hash = 67 * hash + this.filePath.hashCode(); //hash = 67 * hash + this.filePath.hashCode();
return Objects.hash(dataSourceID, filePath); return Objects.hash(dataSourceID, filePath, type);
} }
} }

View File

@ -68,10 +68,10 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
} }
}; };
List<CorrelationAttribute> eamArtifacts; List<OtherOccurrenceNodeData> nodeDataList;
DataContentViewerOtherCasesTableModel() { DataContentViewerOtherCasesTableModel() {
eamArtifacts = new ArrayList<>(); nodeDataList = new ArrayList<>();
} }
@Override @Override
@ -95,7 +95,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
@Override @Override
public int getRowCount() { public int getRowCount() {
return eamArtifacts.size(); return nodeDataList.size();
} }
@Override @Override
@ -105,15 +105,15 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
@Override @Override
public Object getValueAt(int rowIdx, int colIdx) { public Object getValueAt(int rowIdx, int colIdx) {
if (0 == eamArtifacts.size()) { if (0 == nodeDataList.size()) {
return Bundle.DataContentViewerOtherCasesTableModel_noData(); return Bundle.DataContentViewerOtherCasesTableModel_noData();
} }
return mapValueById(rowIdx, TableColumns.values()[colIdx]); return mapValueById(rowIdx, TableColumns.values()[colIdx]);
} }
public Object getRow(int rowIdx) { Object getRow(int rowIdx) {
return eamArtifacts.get(rowIdx); return nodeDataList.get(rowIdx);
} }
/** /**
@ -125,40 +125,39 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
* @return value in the cell * @return value in the cell
*/ */
private Object mapValueById(int rowIdx, TableColumns colId) { private Object mapValueById(int rowIdx, TableColumns colId) {
CorrelationAttribute eamArtifact = eamArtifacts.get(rowIdx); OtherOccurrenceNodeData nodeData = nodeDataList.get(rowIdx);
CorrelationAttributeInstance eamArtifactInstance = eamArtifact.getInstances().get(0);
String value = Bundle.DataContentViewerOtherCasesTableModel_noData(); String value = Bundle.DataContentViewerOtherCasesTableModel_noData();
switch (colId) { switch (colId) {
case CASE_NAME: case CASE_NAME:
if (null != eamArtifactInstance.getCorrelationCase()) { if (null != nodeData.getCaseName()) {
value = eamArtifactInstance.getCorrelationCase().getDisplayName(); value = nodeData.getCaseName();
} }
break; break;
case DEVICE: case DEVICE:
if (null != eamArtifactInstance.getCorrelationDataSource()) { if (null != nodeData.getDeviceID()) {
value = eamArtifactInstance.getCorrelationDataSource().getDeviceID(); value = nodeData.getDeviceID();
} }
break; break;
case DATA_SOURCE: case DATA_SOURCE:
if (null != eamArtifactInstance.getCorrelationDataSource()) { if (null != nodeData.getDataSourceName()) {
value = eamArtifactInstance.getCorrelationDataSource().getName(); value = nodeData.getDataSourceName();
} }
break; break;
case FILE_PATH: case FILE_PATH:
value = eamArtifactInstance.getFilePath(); value = nodeData.getFilePath();
break; break;
case TYPE: case TYPE:
value = eamArtifact.getCorrelationType().getDisplayName(); value = nodeData.getType();
break; break;
case VALUE: case VALUE:
value = eamArtifact.getCorrelationValue(); value = nodeData.getValue();
break; break;
case KNOWN: case KNOWN:
value = eamArtifactInstance.getKnownStatus().getName(); value = nodeData.getKnown().getName();
break; break;
case COMMENT: case COMMENT:
value = eamArtifactInstance.getComment(); value = nodeData.getComment();
break; break;
} }
return value; return value;
@ -170,18 +169,17 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
} }
/** /**
* Add one local central repository artifact to the table. * Add one correlated instance object to the table
* *
* @param eamArtifact central repository artifact to add to the * @param newNodeData data to add to the table
* table
*/ */
public void addEamArtifact(CorrelationAttribute eamArtifact) { void addNodeData(OtherOccurrenceNodeData newNodeData) {
eamArtifacts.add(eamArtifact); nodeDataList.add(newNodeData);
fireTableDataChanged(); fireTableDataChanged();
} }
public void clearTable() { void clearTable() {
eamArtifacts.clear(); nodeDataList.clear();
fireTableDataChanged(); fireTableDataChanged();
} }

View File

@ -0,0 +1,233 @@
/*
* Central Repository
*
* Copyright 2018 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.centralrepository.contentviewer;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
/**
* Class for populating the Other Occurrences tab
*/
class OtherOccurrenceNodeData {
// For now hard code the string for the central repo files type, since
// getting it dynamically can fail.
private static final String FILE_TYPE_STR = "Files";
private final String caseName;
private String deviceID;
private String dataSourceName;
private final String filePath;
private final String typeStr;
private final CorrelationAttribute.Type type;
private final String value;
private TskData.FileKnown known;
private String comment;
private AbstractFile originalAbstractFile = null;
private CorrelationAttributeInstance originalCorrelationInstance = null;
/**
* Create a node from a central repo instance.
* @param instance The central repo instance
* @param type The type of the instance
* @param value The value of the instance
*/
OtherOccurrenceNodeData(CorrelationAttributeInstance instance, CorrelationAttribute.Type type, String value) {
caseName = instance.getCorrelationCase().getDisplayName();
deviceID = instance.getCorrelationDataSource().getDeviceID();
dataSourceName = instance.getCorrelationDataSource().getName();
filePath = instance.getFilePath();
this.typeStr = type.getDisplayName();
this.type = type;
this.value = value;
known = instance.getKnownStatus();
comment = instance.getComment();
originalCorrelationInstance = instance;
}
/**
* Create a node from an abstract file.
* @param newFile The abstract file
* @param autopsyCase The current case
* @throws EamDbException
*/
OtherOccurrenceNodeData(AbstractFile newFile, Case autopsyCase) throws EamDbException {
caseName = autopsyCase.getDisplayName();
try {
DataSource dataSource = autopsyCase.getSleuthkitCase().getDataSource(newFile.getDataSource().getId());
deviceID = dataSource.getDeviceId();
dataSourceName = dataSource.getName();
} catch (TskDataException | TskCoreException ex) {
throw new EamDbException("Error loading data source for abstract file ID " + newFile.getId(), ex);
}
filePath = newFile.getParentPath() + newFile.getName();
typeStr = FILE_TYPE_STR;
this.type = null;
value = newFile.getMd5Hash();
known = newFile.getKnown();
comment = "";
originalAbstractFile = newFile;
}
/**
* Check if this node is a "file" type
* @return true if it is a file type
*/
boolean isFileType() {
return FILE_TYPE_STR.equals(typeStr);
}
/**
* Update the known status for this node
* @param newKnownStatus The new known status
*/
void updateKnown(TskData.FileKnown newKnownStatus) {
known = newKnownStatus;
}
/**
* Update the comment for this node
* @param newComment The new comment
*/
void updateComment(String newComment) {
comment = newComment;
}
/**
* Check if this is a central repo node.
* @return true if this node was created from a central repo instance, false otherwise
*/
boolean isCentralRepoNode() {
return (originalCorrelationInstance != null);
}
/**
* Uses the saved instance plus type and value to make a new CorrelationAttribute.
* Should only be called if isCentralRepoNode() is true.
* @return the newly created CorrelationAttribute
*/
CorrelationAttribute createCorrelationAttribute() throws EamDbException {
if (! isCentralRepoNode() ) {
throw new EamDbException("Can not create CorrelationAttribute for non central repo node");
}
CorrelationAttribute attr = new CorrelationAttribute(type, value);
attr.addInstance(originalCorrelationInstance);
return attr;
}
/**
* Get the case name
* @return the case name
*/
String getCaseName() {
return caseName;
}
/**
* Get the device ID
* @return the device ID
*/
String getDeviceID() {
return deviceID;
}
/**
* Get the data source name
* @return the data source name
*/
String getDataSourceName() {
return dataSourceName;
}
/**
* Get the file path
* @return the file path
*/
String getFilePath() {
return filePath;
}
/**
* Get the type (as a string)
* @return the type
*/
String getType() {
return typeStr;
}
/**
* Get the value (MD5 hash for files)
* @return the value
*/
String getValue() {
return value;
}
/**
* Get the known status
* @return the known status
*/
TskData.FileKnown getKnown() {
return known;
}
/**
* Get the comment
* @return the comment
*/
String getComment() {
return comment;
}
/**
* Get the backing abstract file.
* Should only be called if isCentralRepoNode() is false
* @return the original abstract file
*/
AbstractFile getAbstractFile() throws EamDbException {
if (originalCorrelationInstance == null) {
throw new EamDbException("AbstractFile is null");
}
return originalAbstractFile;
}
/**
* Get the backing CorrelationAttributeInstance.
* Should only be called if isCentralRepoNode() is true
* @return the original CorrelationAttributeInstance
* @throws EamDbException
*/
CorrelationAttributeInstance getCorrelationAttributeInstance() throws EamDbException {
if (originalCorrelationInstance == null) {
throw new EamDbException("CorrelationAttributeInstance is null");
}
return originalCorrelationInstance;
}
}

View File

@ -1772,7 +1772,7 @@ abstract class AbstractSqlEamDb implements EamDb {
} catch (SQLException ex) { } catch (SQLException ex) {
throw new EamDbException("Error getting all artifact instances from instances table", ex); throw new EamDbException("Error getting all artifact instances from instances table", ex);
} finally { } finally {
EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeStatement(preparedStatement);
EamDbUtil.closeResultSet(resultSet); EamDbUtil.closeResultSet(resultSet);
EamDbUtil.closeConnection(conn); EamDbUtil.closeConnection(conn);
} }

View File

@ -221,7 +221,7 @@ public final class PostgresEamDbSettings {
LOGGER.log(Level.SEVERE, "Failed to execute database existance query.", ex); // NON-NLS LOGGER.log(Level.SEVERE, "Failed to execute database existance query.", ex); // NON-NLS
return false; return false;
} finally { } finally {
EamDbUtil.closePreparedStatement(ps); EamDbUtil.closeStatement(ps);
EamDbUtil.closeResultSet(rs); EamDbUtil.closeResultSet(rs);
EamDbUtil.closeConnection(conn); EamDbUtil.closeConnection(conn);
} }

View File

@ -69,6 +69,7 @@ public final class UserPreferences {
private static final String MODE = "AutopsyMode"; // NON-NLS private static final String MODE = "AutopsyMode"; // NON-NLS
private static final String MAX_NUM_OF_LOG_FILE = "MaximumNumberOfLogFiles"; private static final String MAX_NUM_OF_LOG_FILE = "MaximumNumberOfLogFiles";
private static final int LOG_FILE_NUM_INT = 10; private static final int LOG_FILE_NUM_INT = 10;
public static final String GROUP_ITEMS_IN_TREE_BY_DATASOURCE = "GroupItemsInTreeByDataSource"; //NON-NLS
// Prevent instantiation. // Prevent instantiation.
private UserPreferences() { private UserPreferences() {
@ -187,6 +188,14 @@ public final class UserPreferences {
preferences.putInt(NUMBER_OF_FILE_INGEST_THREADS, value); preferences.putInt(NUMBER_OF_FILE_INGEST_THREADS, value);
} }
public static boolean groupItemsInTreeByDatasource() {
return preferences.getBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, false);
}
public static void setGroupItemsInTreeByDatasource(boolean value) {
preferences.putBoolean(GROUP_ITEMS_IN_TREE_BY_DATASOURCE, value);
}
/** /**
* Reads persisted case database connection info. * Reads persisted case database connection info.
* *

View File

@ -26,7 +26,7 @@ LBL_Description=<div style=\"font-size: 12pt; font-family: Verdana, 'Verdana CE'
Format_OperatingSystem_Value={0} version {1} running on {2} Format_OperatingSystem_Value={0} version {1} running on {2}
LBL_Copyright=<div style\="font-size\: 12pt; font-family\: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy&trade; is a digital forensics platform based on The Sleuth Kit&trade; and other tools. <br><ul><li>General Information: <a style\="color\: \#1E2A60;" href\="http\://www.sleuthkit.org">http\://www.sleuthkit.org</a>.</li><li>Training: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright &copy; 2003-2018. </div> LBL_Copyright=<div style\="font-size\: 12pt; font-family\: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy&trade; is a digital forensics platform based on The Sleuth Kit&trade; and other tools. <br><ul><li>General Information: <a style\="color\: \#1E2A60;" href\="http\://www.sleuthkit.org">http\://www.sleuthkit.org</a>.</li><li>Training: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright &copy; 2003-2018. </div>
URL_ON_IMG=http://www.sleuthkit.org/ URL_ON_IMG=http://www.sleuthkit.org/
URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.7.0/ URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.8.0/
FILE_FOR_LOCAL_HELP=file:/// FILE_FOR_LOCAL_HELP=file:///
INDEX_FOR_LOCAL_HELP=/docs/index.html INDEX_FOR_LOCAL_HELP=/docs/index.html
LBL_Close=Close LBL_Close=Close

View File

@ -258,21 +258,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
map.put(EXTENSION.toString(), content.getNameExtension()); map.put(EXTENSION.toString(), content.getNameExtension());
} }
@Override
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<>();
actionsList.addAll(Arrays.asList(super.getActions(true)));
// Create the "Add/Edit Central Repository Comment" menu item if the enabled.
AbstractFile file = content;
if (EamDbUtil.useCentralRepo() && EamArtifactUtil.isSupportedAbstractFileType(file) && file.isFile()) {
actionsList.add(AddEditCentralRepoCommentAction.createAddEditCentralRepoCommentAction(file));
}
return actionsList.toArray(new Action[actionsList.size()]);
}
/** /**
* Used by subclasses of AbstractAbstractFileNode to add the tags property * Used by subclasses of AbstractAbstractFileNode to add the tags property
* to their sheets. * to their sheets.

View File

@ -162,12 +162,12 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
@Override @Override
public AbstractNode visit(DeletedContent dc) { public AbstractNode visit(DeletedContent dc) {
return new DeletedContent.DeletedContentsNode(dc.getSleuthkitCase()); return new DeletedContent.DeletedContentsNode(dc.getSleuthkitCase(), dc.filteringDataSourceObjId());
} }
@Override @Override
public AbstractNode visit(FileSize dc) { public AbstractNode visit(FileSize dc) {
return new FileSize.FileSizeRootNode(dc.getSleuthkitCase()); return new FileSize.FileSizeRootNode(dc.getSleuthkitCase(), dc.filteringDataSourceObjId());
} }
@Override @Override
@ -192,22 +192,27 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
@Override @Override
public AbstractNode visit(Tags tagsNodeKey) { public AbstractNode visit(Tags tagsNodeKey) {
return tagsNodeKey.new RootNode(); return tagsNodeKey.new RootNode(tagsNodeKey.filteringDataSourceObjId());
} }
@Override @Override
public AbstractNode visit(DataSources i) { public AbstractNode visit(DataSources i) {
return new DataSourcesNode(); return new DataSourcesNode(i.filteringDataSourceObjId());
} }
@Override
public AbstractNode visit(DataSourceGrouping datasourceGrouping) {
return new DataSourceGroupingNode(datasourceGrouping.getDataSource());
}
@Override @Override
public AbstractNode visit(Views v) { public AbstractNode visit(Views v) {
return new ViewsNode(v.getSleuthkitCase()); return new ViewsNode(v.getSleuthkitCase(), v.filteringDataSourceObjId());
} }
@Override @Override
public AbstractNode visit(Results r) { public AbstractNode visit(Results results) {
return new ResultsNode(r.getSleuthkitCase()); return new ResultsNode(results.getSleuthkitCase(), results.filteringDataSourceObjId() );
} }
@Override @Override

View File

@ -28,6 +28,8 @@ import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
public interface AutopsyItemVisitor<T> { public interface AutopsyItemVisitor<T> {
T visit(DataSources i); T visit(DataSources i);
T visit(DataSourceGrouping datasourceGrouping);
T visit(Views v); T visit(Views v);
@ -173,6 +175,11 @@ public interface AutopsyItemVisitor<T> {
return defaultVisit(v); return defaultVisit(v);
} }
@Override
public T visit(DataSourceGrouping datasourceGrouping) {
return defaultVisit(datasourceGrouping);
}
@Override @Override
public T visit(Results r) { public T visit(Results r) {
return defaultVisit(r); return defaultVisit(r);

View File

@ -0,0 +1,146 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.logging.Level;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitVisitableItem;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Child factory to create the top level children of the autopsy tree
*
*/
public class AutopsyTreeChildrenFactory extends ChildFactory.Detachable<Object> {
private static final Logger logger = Logger.getLogger(AutopsyTreeChildrenFactory.class.getName());
private final SleuthkitCase tskCase;
/**
* Constructs the child factory
* @param tskCase
*/
public AutopsyTreeChildrenFactory(SleuthkitCase tskCase) {
this.tskCase = tskCase;
}
/**
* Listener for handling DATA_SOURCE_ADDED events.
*/
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
refreshChildren();
}
}
};
@Override
protected void addNotify() {
super.addNotify();
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
}
@Override
protected void removeNotify() {
super.removeNotify();
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
}
/**
* Creates keys for the top level children.
*
* @param list list of keys created
* @return true, indicating that the key list is complete
*/
@Override
protected boolean createKeys(List<Object> list) {
try {
if (UserPreferences.groupItemsInTreeByDatasource()) {
List<DataSource> dataSources = tskCase.getDataSources();
List<DataSourceGrouping> keys = new ArrayList<>();
dataSources.forEach((datasource) -> {
keys.add(new DataSourceGrouping(datasource));
});
list.addAll(keys);
list.add(new Reports());
} else {
List<AutopsyVisitableItem> keys = new ArrayList<>(Arrays.asList(
new DataSources(),
new Views(tskCase),
new Results(tskCase),
new Tags(),
new Reports()));
list.addAll(keys);
}
} catch (TskCoreException tskCoreException) {
logger.log(Level.SEVERE, "Error getting datas sources list from the database.", tskCoreException);
}
return true;
}
/**
* Creates nodes for the top level Key
*
* @param key
*
* @return Node for the key, null if key is unknown.
*/
@Override
protected Node createNodeForKey(Object key) {
if (key instanceof SleuthkitVisitableItem) {
return ((SleuthkitVisitableItem) key).accept(new RootContentChildren.CreateSleuthkitNodeVisitor());
} else if (key instanceof AutopsyVisitableItem) {
return ((AutopsyVisitableItem) key).accept(new RootContentChildren.CreateAutopsyNodeVisitor());
}
else {
logger.log(Level.SEVERE, "Unknown key type ", key.getClass().getName());
return null;
}
}
/**
* Refresh the children
*/
public void refreshChildren() {
refresh(true);
}
}

View File

@ -221,11 +221,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
actionsList.addAll(Arrays.asList(super.getActions(context))); actionsList.addAll(Arrays.asList(super.getActions(context)));
AbstractFile file = getLookup().lookup(AbstractFile.class); AbstractFile file = getLookup().lookup(AbstractFile.class);
// Create the "Add/Edit Central Repository Comment" menu item if the enabled.
if (file != null && file.isFile() && EamDbUtil.useCentralRepo()) {
actionsList.add(AddEditCentralRepoCommentAction.createAddEditCentralRepoCommentAction(file));
}
//if this artifact has a time stamp add the action to view it in the timeline //if this artifact has a time stamp add the action to view it in the timeline
try { try {
if (ViewArtifactInTimelineAction.hasSupportedTimeStamp(artifact)) { if (ViewArtifactInTimelineAction.hasSupportedTimeStamp(artifact)) {

View File

@ -56,6 +56,7 @@ DataModelActionsFactory.viewNewWin.text=View in New Window
DataModelActionsFactory.openExtViewer.text=Open in External Viewer DataModelActionsFactory.openExtViewer.text=Open in External Viewer
DataModelActionsFactory.srfFileSameMD5.text=Search for files with the same MD5 hash DataModelActionsFactory.srfFileSameMD5.text=Search for files with the same MD5 hash
DataSourcesNode.name=Data Sources DataSourcesNode.name=Data Sources
DataSourcesNode.group_by_datasource.name=Data Source Files
DataSourcesNode.createSheet.name.name=Name DataSourcesNode.createSheet.name.name=Name
DataSourcesNode.createSheet.name.displayName=Name DataSourcesNode.createSheet.name.displayName=Name
DataSourcesNode.createSheet.name.desc=no description DataSourcesNode.createSheet.name.desc=no description

View File

@ -57,6 +57,7 @@ DataModelActionsFactory.viewNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30
DataModelActionsFactory.openExtViewer.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u306b\u8868\u793a DataModelActionsFactory.openExtViewer.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u306b\u8868\u793a
DataModelActionsFactory.srfFileSameMD5.text=\u540c\u3058MD5\u30cf\u30c3\u30b7\u30e5\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22 DataModelActionsFactory.srfFileSameMD5.text=\u540c\u3058MD5\u30cf\u30c3\u30b7\u30e5\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22
DataSourcesNode.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9 DataSourcesNode.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
DataSourcesNode.group_by_datasource.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb
DataSourcesNode.createSheet.name.name=\u540d\u524d DataSourcesNode.createSheet.name.name=\u540d\u524d
DataSourcesNode.createSheet.name.displayName=\u540d\u524d DataSourcesNode.createSheet.name.displayName=\u540d\u524d
DataSourcesNode.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093 DataSourcesNode.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093

View File

@ -0,0 +1,45 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.datamodel;
import org.sleuthkit.datamodel.DataSource;
/**
* A top level UI grouping of Files, Views, Results, Tags
* for 'Group by Data Source' view of the tree.
*
*/
public class DataSourceGrouping implements AutopsyVisitableItem {
private final DataSource dataSource;
public DataSourceGrouping(DataSource dataSource) {
this.dataSource = dataSource;
}
DataSource getDataSource() {
return this.dataSource;
}
@Override
public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@ -0,0 +1,99 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 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.datamodel;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.LocalFilesDataSource;
/**
* Data source grouping node - an optional grouping node in the data tree view
*
*/
class DataSourceGroupingNode extends DisplayableItemNode {
private static final Logger logger = Logger.getLogger(DataSourceGroupingNode.class.getName());
/**
* Creates a data source grouping node for the given data source.
*
* @param dataSource specifies the data source
*/
DataSourceGroupingNode(DataSource dataSource) {
super (Optional.ofNullable(createDSGroupingNodeChildren(dataSource))
.orElse(new RootContentChildren(Arrays.asList(Collections.EMPTY_LIST))));
if (dataSource instanceof Image) {
Image image = (Image) dataSource;
super.setName(image.getName());
super.setDisplayName(image.getName());
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png");
} else if (dataSource instanceof LocalFilesDataSource) {
LocalFilesDataSource localFilesDataSource = (LocalFilesDataSource) dataSource;
super.setName(localFilesDataSource.getName());
super.setDisplayName(localFilesDataSource.getName());
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png");
}
}
@Override
public boolean isLeafTypeNode() {
return false;
}
private static RootContentChildren createDSGroupingNodeChildren(DataSource dataSource) {
long dsObjId = dataSource.getId();
try {
return new RootContentChildren(Arrays.asList(
new DataSources(dsObjId),
new Views(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId),
new Results(Case.getCurrentCaseThrows().getSleuthkitCase(), dsObjId),
new Tags(dsObjId) )
);
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Error getting open case.", ex); //NON-NLS
return null;
}
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
public String getItemType() {
return getClass().getName();
}
}

View File

@ -23,9 +23,20 @@ package org.sleuthkit.autopsy.datamodel;
*/ */
public class DataSources implements AutopsyVisitableItem { public class DataSources implements AutopsyVisitableItem {
private final long datasourceObjId;
public DataSources() { public DataSources() {
this(0);
} }
public DataSources(long datasourceObjId) {
this.datasourceObjId = datasourceObjId;
}
long filteringDataSourceObjId() {
return this.datasourceObjId;
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> visitor) { public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
@ -33,6 +34,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
/** /**
* Nodes for the images * Nodes for the images
@ -40,22 +42,27 @@ import org.sleuthkit.datamodel.TskCoreException;
public class DataSourcesNode extends DisplayableItemNode { public class DataSourcesNode extends DisplayableItemNode {
public static final String NAME = NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.name"); public static final String NAME = NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.name");
private final String displayName;
// NOTE: The images passed in via argument will be ignored. // NOTE: The images passed in via argument will be ignored.
@Deprecated @Deprecated
public DataSourcesNode(List<Content> images) { public DataSourcesNode(List<Content> images) {
super(new DataSourcesNodeChildren(), Lookups.singleton(NAME)); this(0);
init();
} }
public DataSourcesNode() { public DataSourcesNode() {
super(new DataSourcesNodeChildren(), Lookups.singleton(NAME)); this(0);
init();
} }
public DataSourcesNode(long dsObjId) {
super(new DataSourcesNodeChildren(dsObjId), Lookups.singleton(NAME));
displayName = (dsObjId > 0) ? NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.group_by_datasource.name") : NAME;
init();
}
private void init() { private void init() {
setName(NAME); setName(NAME);
setDisplayName(NAME); setDisplayName(displayName);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); //NON-NLS
} }
@ -70,14 +77,20 @@ public class DataSourcesNode extends DisplayableItemNode {
public static class DataSourcesNodeChildren extends AbstractContentChildren<Content> { public static class DataSourcesNodeChildren extends AbstractContentChildren<Content> {
private static final Logger logger = Logger.getLogger(DataSourcesNodeChildren.class.getName()); private static final Logger logger = Logger.getLogger(DataSourcesNodeChildren.class.getName());
private final long datasourceObjId;
List<Content> currentKeys; List<Content> currentKeys;
public DataSourcesNodeChildren() { public DataSourcesNodeChildren() {
super(); this(0);
this.currentKeys = new ArrayList<>();
} }
public DataSourcesNodeChildren(long dsObjId) {
super();
this.currentKeys = new ArrayList<>();
this.datasourceObjId = dsObjId;
}
private final PropertyChangeListener pcl = new PropertyChangeListener() { private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
@ -103,9 +116,15 @@ public class DataSourcesNode extends DisplayableItemNode {
private void reloadKeys() { private void reloadKeys() {
try { try {
currentKeys = Case.getCurrentCaseThrows().getDataSources(); if (datasourceObjId == 0) {
currentKeys = Case.getCurrentCaseThrows().getDataSources();
}
else {
Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getDataSource(datasourceObjId);
currentKeys = new ArrayList<>(Arrays.asList(content));
}
setKeys(currentKeys); setKeys(currentKeys);
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException | TskDataException ex) {
logger.log(Level.SEVERE, "Error getting data sources: {0}", ex.getMessage()); // NON-NLS logger.log(Level.SEVERE, "Error getting data sources: {0}", ex.getMessage()); // NON-NLS
setKeys(Collections.<Content>emptySet()); setKeys(Collections.<Content>emptySet());
} }

View File

@ -61,6 +61,7 @@ import org.sleuthkit.datamodel.TskData;
public class DeletedContent implements AutopsyVisitableItem { public class DeletedContent implements AutopsyVisitableItem {
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final long datasourceObjId;
@NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System", @NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System",
"DeletedContent.allDelFilter.text=All"}) "DeletedContent.allDelFilter.text=All"})
@ -101,9 +102,18 @@ public class DeletedContent implements AutopsyVisitableItem {
} }
public DeletedContent(SleuthkitCase skCase) { public DeletedContent(SleuthkitCase skCase) {
this.skCase = skCase; this(skCase, 0);
} }
public DeletedContent(SleuthkitCase skCase, long dsObjId) {
this.skCase = skCase;
this.datasourceObjId = dsObjId;
}
long filteringDataSourceObjId() {
return this.datasourceObjId;
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> visitor) { public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
@ -118,8 +128,8 @@ public class DeletedContent implements AutopsyVisitableItem {
@NbBundle.Messages("DeletedContent.deletedContentsNode.name=Deleted Files") @NbBundle.Messages("DeletedContent.deletedContentsNode.name=Deleted Files")
private static final String NAME = Bundle.DeletedContent_deletedContentsNode_name(); private static final String NAME = Bundle.DeletedContent_deletedContentsNode_name();
DeletedContentsNode(SleuthkitCase skCase) { DeletedContentsNode(SleuthkitCase skCase, long datasourceObjId) {
super(Children.create(new DeletedContentsChildren(skCase), true), Lookups.singleton(NAME)); super(Children.create(new DeletedContentsChildren(skCase, datasourceObjId), true), Lookups.singleton(NAME));
super.setName(NAME); super.setName(NAME);
super.setDisplayName(NAME); super.setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS
@ -164,11 +174,13 @@ public class DeletedContent implements AutopsyVisitableItem {
private SleuthkitCase skCase; private SleuthkitCase skCase;
private Observable notifier; private Observable notifier;
private final long datasourceObjId;
// true if we have already told user that not all files will be shown // true if we have already told user that not all files will be shown
private static volatile boolean maxFilesDialogShown = false; private static volatile boolean maxFilesDialogShown = false;
public DeletedContentsChildren(SleuthkitCase skCase) { public DeletedContentsChildren(SleuthkitCase skCase, long dsObjId) {
this.skCase = skCase; this.skCase = skCase;
this.datasourceObjId = dsObjId;
this.notifier = new DeletedContentsChildrenObservable(); this.notifier = new DeletedContentsChildrenObservable();
} }
@ -257,24 +269,27 @@ public class DeletedContent implements AutopsyVisitableItem {
@Override @Override
protected Node createNodeForKey(DeletedContent.DeletedContentFilter key) { protected Node createNodeForKey(DeletedContent.DeletedContentFilter key) {
return new DeletedContentNode(skCase, key, notifier); return new DeletedContentNode(skCase, key, notifier, datasourceObjId);
} }
public class DeletedContentNode extends DisplayableItemNode { public class DeletedContentNode extends DisplayableItemNode {
private final DeletedContent.DeletedContentFilter filter; private final DeletedContent.DeletedContentFilter filter;
private final long datasourceObjId;
// Use version that has observer for updates // Use version that has observer for updates
@Deprecated @Deprecated
DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter) { DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, long dsObjId) {
super(Children.create(new DeletedContentChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName())); super(Children.create(new DeletedContentChildren(filter, skCase, null, dsObjId ), true), Lookups.singleton(filter.getDisplayName()));
this.filter = filter; this.filter = filter;
this.datasourceObjId = dsObjId;
init(); init();
} }
DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, Observable o) { DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, Observable o, long dsObjId) {
super(Children.create(new DeletedContentChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); super(Children.create(new DeletedContentChildren(filter, skCase, o, dsObjId), true), Lookups.singleton(filter.getDisplayName()));
this.filter = filter; this.filter = filter;
this.datasourceObjId = dsObjId;
init(); init();
o.addObserver(new DeletedContentNodeObserver()); o.addObserver(new DeletedContentNodeObserver());
} }
@ -299,7 +314,7 @@ public class DeletedContent implements AutopsyVisitableItem {
private void updateDisplayName() { private void updateDisplayName() {
//get count of children without preloading all children nodes //get count of children without preloading all children nodes
final long count = DeletedContentChildren.calculateItems(skCase, filter); final long count = DeletedContentChildren.calculateItems(skCase, filter, datasourceObjId);
//final long count = getChildren().getNodesCount(true); //final long count = getChildren().getNodesCount(true);
super.setDisplayName(filter.getDisplayName() + " (" + count + ")"); super.setDisplayName(filter.getDisplayName() + " (" + count + ")");
} }
@ -351,11 +366,13 @@ public class DeletedContent implements AutopsyVisitableItem {
private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName()); private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName());
private static final int MAX_OBJECTS = 10001; private static final int MAX_OBJECTS = 10001;
private final Observable notifier; private final Observable notifier;
private final long datasourceObjId;
DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o) { DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o, long datasourceObjId) {
this.skCase = skCase; this.skCase = skCase;
this.filter = filter; this.filter = filter;
this.notifier = o; this.notifier = o;
this.datasourceObjId = datasourceObjId;
} }
private final Observer observer = new DeletedContentChildrenObserver(); private final Observer observer = new DeletedContentChildrenObserver();
@ -366,7 +383,7 @@ public class DeletedContent implements AutopsyVisitableItem {
@Override @Override
public void update(Observable o, Object arg) { public void update(Observable o, Object arg) {
refresh(true); refresh(true);
} }
} }
@Override @Override
@ -405,7 +422,7 @@ public class DeletedContent implements AutopsyVisitableItem {
return true; return true;
} }
static private String makeQuery(DeletedContent.DeletedContentFilter filter) { static private String makeQuery(DeletedContent.DeletedContentFilter filter, long filteringDSObjId) {
String query = ""; String query = "";
switch (filter) { switch (filter) {
case FS_DELETED_FILTER: case FS_DELETED_FILTER:
@ -443,6 +460,10 @@ public class DeletedContent implements AutopsyVisitableItem {
+ " OR known IS NULL)"; //NON-NLS + " OR known IS NULL)"; //NON-NLS
} }
if (UserPreferences.groupItemsInTreeByDatasource()) {
query += " AND data_source_obj_id = " + filteringDSObjId;
}
query += " LIMIT " + MAX_OBJECTS; //NON-NLS query += " LIMIT " + MAX_OBJECTS; //NON-NLS
return query; return query;
} }
@ -450,7 +471,7 @@ public class DeletedContent implements AutopsyVisitableItem {
private List<AbstractFile> runFsQuery() { private List<AbstractFile> runFsQuery() {
List<AbstractFile> ret = new ArrayList<>(); List<AbstractFile> ret = new ArrayList<>();
String query = makeQuery(filter); String query = makeQuery(filter, datasourceObjId);
try { try {
ret = skCase.findAllFilesWhere(query); ret = skCase.findAllFilesWhere(query);
} catch (TskCoreException e) { } catch (TskCoreException e) {
@ -469,9 +490,9 @@ public class DeletedContent implements AutopsyVisitableItem {
* *
* @return * @return
*/ */
static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter) { static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter, long datasourceObjId) {
try { try {
return sleuthkitCase.countFilesWhere(makeQuery(filter)); return sleuthkitCase.countFilesWhere(makeQuery(filter, datasourceObjId));
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting deleted files search view count", ex); //NON-NLS logger.log(Level.SEVERE, "Error getting deleted files search view count", ex); //NON-NLS
return 0; return 0;

View File

@ -61,6 +61,8 @@ public interface DisplayableItemNodeVisitor<T> {
*/ */
T visit(ViewsNode vn); T visit(ViewsNode vn);
T visit(DataSourceGroupingNode dataSourceGroupingNode);
T visit(org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileExtensionNode fsfn); T visit(org.sleuthkit.autopsy.datamodel.FileTypesByExtension.FileExtensionNode fsfn);
T visit(DeletedContentNode dcn); T visit(DeletedContentNode dcn);
@ -336,6 +338,11 @@ public interface DisplayableItemNodeVisitor<T> {
return defaultVisit(vn); return defaultVisit(vn);
} }
@Override
public T visit(DataSourceGroupingNode dataSourceGroupingNode) {
return defaultVisit(dataSourceGroupingNode);
}
@Override @Override
public T visit(ResultsNode rn) { public T visit(ResultsNode rn) {
return defaultVisit(rn); return defaultVisit(rn);

View File

@ -40,6 +40,7 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
@ -86,10 +87,29 @@ public class EmailExtracted implements AutopsyVisitableItem {
} }
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final EmailResults emailResults; private final EmailResults emailResults;
private final long datasourceObjId;
/**
* Constructor
*
* @param skCase Case DB
*/
public EmailExtracted(SleuthkitCase skCase) { public EmailExtracted(SleuthkitCase skCase) {
this(skCase, 0);
}
/**
* Constructor
*
* @param skCase Case DB
* @param objId Object id of the data source
*
*/
public EmailExtracted(SleuthkitCase skCase, long objId) {
this.skCase = skCase; this.skCase = skCase;
this.datasourceObjId = objId;
emailResults = new EmailResults(); emailResults = new EmailResults();
} }
@ -141,6 +161,9 @@ public class EmailExtracted implements AutopsyVisitableItem {
+ "attribute_type_id=" + pathAttrId //NON-NLS + "attribute_type_id=" + pathAttrId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
if (UserPreferences.groupItemsInTreeByDatasource()) {
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
}
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
ResultSet resultSet = dbQuery.getResultSet(); ResultSet resultSet = dbQuery.getResultSet();

View File

@ -35,9 +35,11 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
@ -57,12 +59,31 @@ import org.sleuthkit.datamodel.TskException;
public class ExtractedContent implements AutopsyVisitableItem { public class ExtractedContent implements AutopsyVisitableItem {
private SleuthkitCase skCase; // set to null after case has been closed private SleuthkitCase skCase; // set to null after case has been closed
private Blackboard blackboard;
public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text");
private final long datasourceObjId;
/**
* Constructs extracted content object
*
* @param skCase Case DB
*/
public ExtractedContent(SleuthkitCase skCase) { public ExtractedContent(SleuthkitCase skCase) {
this.skCase = skCase; this(skCase, 0);
} }
/**
* Constructs extracted content object
*
* @param skCase Case DB
* @param objId Object id of the parent datasource
*/
public ExtractedContent(SleuthkitCase skCase, long objId) {
this.skCase = skCase;
this.datasourceObjId = objId;
this.blackboard = skCase.getBlackboard();
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> visitor) { public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
@ -270,7 +291,10 @@ public class ExtractedContent implements AutopsyVisitableItem {
//TEST COMMENT //TEST COMMENT
if (skCase != null) { if (skCase != null) {
try { try {
List<BlackboardArtifact.Type> types = skCase.getArtifactTypesInUse(); List<BlackboardArtifact.Type> types = (UserPreferences.groupItemsInTreeByDatasource()) ?
blackboard.getArtifactTypesInUse(datasourceObjId) :
skCase.getArtifactTypesInUse() ;
types.removeAll(doNotShow); types.removeAll(doNotShow);
Collections.sort(types, Collections.sort(types,
new Comparator<BlackboardArtifact.Type>() { new Comparator<BlackboardArtifact.Type>() {
@ -332,7 +356,9 @@ public class ExtractedContent implements AutopsyVisitableItem {
// a performance increase might be had by adding a // a performance increase might be had by adding a
// "getBlackboardArtifactCount()" method to skCase // "getBlackboardArtifactCount()" method to skCase
try { try {
this.childCount = skCase.getBlackboardArtifactsTypeCount(type.getTypeID()); this.childCount = UserPreferences.groupItemsInTreeByDatasource() ?
blackboard.getArtifactsCount(type.getTypeID(), datasourceObjId) :
skCase.getBlackboardArtifactsTypeCount(type.getTypeID());
} catch (TskException ex) { } catch (TskException ex) {
Logger.getLogger(TypeNode.class.getName()) Logger.getLogger(TypeNode.class.getName())
.log(Level.WARNING, "Error getting child count", ex); //NON-NLS .log(Level.WARNING, "Error getting child count", ex); //NON-NLS
@ -454,7 +480,10 @@ public class ExtractedContent implements AutopsyVisitableItem {
protected boolean createKeys(List<BlackboardArtifact> list) { protected boolean createKeys(List<BlackboardArtifact> list) {
if (skCase != null) { if (skCase != null) {
try { try {
List<BlackboardArtifact> arts = skCase.getBlackboardArtifacts(type.getTypeID()); List<BlackboardArtifact> arts =
UserPreferences.groupItemsInTreeByDatasource() ?
blackboard.getArtifacts(type.getTypeID(), datasourceObjId) :
skCase.getBlackboardArtifacts(type.getTypeID());
list.addAll(arts); list.addAll(arts);
} catch (TskException ex) { } catch (TskException ex) {
Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS Logger.getLogger(ArtifactFactory.class.getName()).log(Level.SEVERE, "Couldn't get blackboard artifacts from database", ex); //NON-NLS

View File

@ -61,6 +61,7 @@ import org.sleuthkit.datamodel.VirtualDirectory;
public class FileSize implements AutopsyVisitableItem { public class FileSize implements AutopsyVisitableItem {
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final long datasourceObjId;
public enum FileSizeFilter implements AutopsyVisitableItem { public enum FileSizeFilter implements AutopsyVisitableItem {
@ -97,9 +98,14 @@ public class FileSize implements AutopsyVisitableItem {
} }
public FileSize(SleuthkitCase skCase) { public FileSize(SleuthkitCase skCase) {
this.skCase = skCase; this(skCase, 0);
} }
public FileSize(SleuthkitCase skCase, long dsObjId) {
this.skCase = skCase;
this.datasourceObjId = dsObjId;
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> visitor) { public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
@ -109,6 +115,9 @@ public class FileSize implements AutopsyVisitableItem {
return this.skCase; return this.skCase;
} }
long filteringDataSourceObjId() {
return this.datasourceObjId;
}
/* /*
* Root node. Children are nodes for specific sizes. * Root node. Children are nodes for specific sizes.
*/ */
@ -116,8 +125,8 @@ public class FileSize implements AutopsyVisitableItem {
private static final String NAME = NbBundle.getMessage(FileSize.class, "FileSize.fileSizeRootNode.name"); private static final String NAME = NbBundle.getMessage(FileSize.class, "FileSize.fileSizeRootNode.name");
FileSizeRootNode(SleuthkitCase skCase) { FileSizeRootNode(SleuthkitCase skCase, long datasourceObjId) {
super(Children.create(new FileSizeRootChildren(skCase), true), Lookups.singleton(NAME)); super(Children.create(new FileSizeRootChildren(skCase, datasourceObjId), true), Lookups.singleton(NAME));
super.setName(NAME); super.setName(NAME);
super.setDisplayName(NAME); super.setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS
@ -161,10 +170,12 @@ public class FileSize implements AutopsyVisitableItem {
public static class FileSizeRootChildren extends ChildFactory<org.sleuthkit.autopsy.datamodel.FileSize.FileSizeFilter> { public static class FileSizeRootChildren extends ChildFactory<org.sleuthkit.autopsy.datamodel.FileSize.FileSizeFilter> {
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final long datasourceObjId;
private Observable notifier; private Observable notifier;
public FileSizeRootChildren(SleuthkitCase skCase) { public FileSizeRootChildren(SleuthkitCase skCase, long datasourceObjId) {
this.skCase = skCase; this.skCase = skCase;
this.datasourceObjId = datasourceObjId;
notifier = new FileSizeRootChildrenObservable(); notifier = new FileSizeRootChildrenObservable();
} }
@ -248,7 +259,7 @@ public class FileSize implements AutopsyVisitableItem {
@Override @Override
protected Node createNodeForKey(FileSizeFilter key) { protected Node createNodeForKey(FileSizeFilter key) {
return new FileSizeNode(skCase, key, notifier); return new FileSizeNode(skCase, key, notifier, datasourceObjId);
} }
/* /*
@ -257,12 +268,14 @@ public class FileSize implements AutopsyVisitableItem {
public class FileSizeNode extends DisplayableItemNode { public class FileSizeNode extends DisplayableItemNode {
private FileSizeFilter filter; private FileSizeFilter filter;
private final long datasourceObjId;
// use version with observer instead so that it updates // use version with observer instead so that it updates
@Deprecated @Deprecated
FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter) { FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, long datasourceObjId) {
super(Children.create(new FileSizeChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName())); super(Children.create(new FileSizeChildren(filter, skCase, null, datasourceObjId), true), Lookups.singleton(filter.getDisplayName()));
this.filter = filter; this.filter = filter;
this.datasourceObjId = datasourceObjId;
init(); init();
} }
@ -272,10 +285,12 @@ public class FileSize implements AutopsyVisitableItem {
* @param filter * @param filter
* @param o Observable that provides updates when events are * @param o Observable that provides updates when events are
* fired * fired
* @param datasourceObjId filter by data source, if configured in user preferences
*/ */
FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o) { FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o, long datasourceObjId) {
super(Children.create(new FileSizeChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); super(Children.create(new FileSizeChildren(filter, skCase, o, datasourceObjId), true), Lookups.singleton(filter.getDisplayName()));
this.filter = filter; this.filter = filter;
this.datasourceObjId = datasourceObjId;
init(); init();
o.addObserver(new FileSizeNodeObserver()); o.addObserver(new FileSizeNodeObserver());
} }
@ -309,7 +324,7 @@ public class FileSize implements AutopsyVisitableItem {
} }
private void updateDisplayName() { private void updateDisplayName() {
final long numVisibleChildren = FileSizeChildren.calculateItems(skCase, filter); final long numVisibleChildren = FileSizeChildren.calculateItems(skCase, filter, datasourceObjId);
super.setDisplayName(filter.getDisplayName() + " (" + numVisibleChildren + ")"); super.setDisplayName(filter.getDisplayName() + " (" + numVisibleChildren + ")");
} }
@ -349,6 +364,7 @@ public class FileSize implements AutopsyVisitableItem {
private final SleuthkitCase skCase; private final SleuthkitCase skCase;
private final FileSizeFilter filter; private final FileSizeFilter filter;
private final Observable notifier; private final Observable notifier;
private final long datasourceObjId;
private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName()); private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName());
/** /**
@ -358,10 +374,12 @@ public class FileSize implements AutopsyVisitableItem {
* @param o Observable that provides updates when new files are * @param o Observable that provides updates when new files are
* added to case * added to case
*/ */
FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o) { FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o, long dsObjId) {
this.skCase = skCase; this.skCase = skCase;
this.filter = filter; this.filter = filter;
this.notifier = o; this.notifier = o;
this.datasourceObjId = dsObjId;
} }
@Override @Override
@ -395,7 +413,7 @@ public class FileSize implements AutopsyVisitableItem {
return true; return true;
} }
private static String makeQuery(FileSizeFilter filter) { private static String makeQuery(FileSizeFilter filter, long filteringDSObjId) {
String query; String query;
switch (filter) { switch (filter) {
case SIZE_50_200: case SIZE_50_200:
@ -427,6 +445,11 @@ public class FileSize implements AutopsyVisitableItem {
query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + ")"; //NON-NLS query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + ")"; //NON-NLS
} }
// filter by datasource if indicated in user preferences
if (UserPreferences.groupItemsInTreeByDatasource()) {
query += " AND data_source_obj_id = " + filteringDSObjId;
}
return query; return query;
} }
@ -434,7 +457,7 @@ public class FileSize implements AutopsyVisitableItem {
List<AbstractFile> ret = new ArrayList<>(); List<AbstractFile> ret = new ArrayList<>();
try { try {
String query = makeQuery(filter); String query = makeQuery(filter, datasourceObjId);
ret = skCase.findAllFilesWhere(query); ret = skCase.findAllFilesWhere(query);
} catch (Exception e) { } catch (Exception e) {
@ -449,9 +472,9 @@ public class FileSize implements AutopsyVisitableItem {
* *
* @return * @return
*/ */
static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter) { static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter, long datasourceObjId) {
try { try {
return sleuthkitCase.countFilesWhere(makeQuery(filter)); return sleuthkitCase.countFilesWhere(makeQuery(filter, datasourceObjId));
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting files by size search view count", ex); //NON-NLS logger.log(Level.SEVERE, "Error getting files by size search view count", ex); //NON-NLS
return 0; return 0;

View File

@ -72,11 +72,18 @@ public final class FileTypes implements AutopsyVisitableItem {
private final SleuthkitCase skCase; private final SleuthkitCase skCase;
private final long datasourceObjId;
FileTypes(SleuthkitCase skCase) { FileTypes(SleuthkitCase skCase) {
this.skCase = skCase; this(skCase, 0);
updateShowCounts();
} }
FileTypes(SleuthkitCase skCase, long dsObjId) {
this.skCase = skCase;
this.datasourceObjId = dsObjId;
updateShowCounts();
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> visitor) { public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
@ -86,6 +93,9 @@ public final class FileTypes implements AutopsyVisitableItem {
return skCase; return skCase;
} }
long filteringDataSourceObjId() {
return this.datasourceObjId;
}
/** /**
* Check the db to determine if the nodes should show child counts. * Check the db to determine if the nodes should show child counts.
*/ */

View File

@ -69,6 +69,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
return visitor.visit(this); return visitor.visit(this);
} }
long filteringDataSourceObjId() {
return typesRoot.filteringDataSourceObjId();
}
/** /**
* Listens for case and ingest invest. Updates observers when events are * Listens for case and ingest invest. Updates observers when events are
* fired. FileType and FileTypes nodes are all listening to this. * fired. FileType and FileTypes nodes are all listening to this.
@ -359,6 +363,9 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
+ (UserPreferences.hideKnownFilesInViewsTree() + (UserPreferences.hideKnownFilesInViewsTree()
? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")" ? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
: " ") : " ")
+ (UserPreferences.groupItemsInTreeByDatasource()
? " AND data_source_obj_id = " + filteringDataSourceObjId()
: " ")
+ " AND (extension IN (" + filter.getFilter().stream() + " AND (extension IN (" + filter.getFilter().stream()
.map(String::toLowerCase) .map(String::toLowerCase)
.map(s -> "'"+StringUtils.substringAfter(s, ".")+"'") .map(s -> "'"+StringUtils.substringAfter(s, ".")+"'")

View File

@ -42,6 +42,7 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree; import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree;
import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree; import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -91,15 +92,16 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
* @return The base expression to be used in the where clause of queries for * @return The base expression to be used in the where clause of queries for
* files by mime type. * files by mime type.
*/ */
static private String createBaseWhereExpr() { private String createBaseWhereExpr() {
return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
+ " AND (type IN (" + " AND (type IN ("
+ TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + ","
+ TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal() + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
+ (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal())) + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
+ "))" + "))"
+ ( UserPreferences.groupItemsInTreeByDatasource() ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
+ (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : ""); + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
} }
@ -188,6 +190,10 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
return visitor.visit(this); return visitor.visit(this);
} }
long filteringDataSourceObjId() {
return typesRoot.filteringDataSourceObjId();
}
/** /**
* Method to check if the node in question is a ByMimeTypeNode which is * Method to check if the node in question is a ByMimeTypeNode which is
* empty. * empty.

View File

@ -42,6 +42,7 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
@ -63,9 +64,29 @@ public class HashsetHits implements AutopsyVisitableItem {
private static final Logger logger = Logger.getLogger(HashsetHits.class.getName()); private static final Logger logger = Logger.getLogger(HashsetHits.class.getName());
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final HashsetResults hashsetResults; private final HashsetResults hashsetResults;
private final long datasourceObjId;
/**
* Constructor
*
* @param skCase Case DB
*
*/
public HashsetHits(SleuthkitCase skCase) { public HashsetHits(SleuthkitCase skCase) {
this(skCase, 0);
}
/**
* Constructor
*
* @param skCase Case DB
* @param objId Object id of the data source
*
*/
public HashsetHits(SleuthkitCase skCase, long objId) {
this.skCase = skCase; this.skCase = skCase;
this.datasourceObjId = objId;
hashsetResults = new HashsetResults(); hashsetResults = new HashsetResults();
} }
@ -120,7 +141,10 @@ public class HashsetHits implements AutopsyVisitableItem {
+ "attribute_type_id=" + setNameId //NON-NLS + "attribute_type_id=" + setNameId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
if (UserPreferences.groupItemsInTreeByDatasource()) {
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
}
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
ResultSet resultSet = dbQuery.getResultSet(); ResultSet resultSet = dbQuery.getResultSet();
synchronized (hashSetHitsMap) { synchronized (hashSetHitsMap) {

View File

@ -42,6 +42,7 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
@ -59,9 +60,28 @@ public class InterestingHits implements AutopsyVisitableItem {
private static final Logger logger = Logger.getLogger(InterestingHits.class.getName()); private static final Logger logger = Logger.getLogger(InterestingHits.class.getName());
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final InterestingResults interestingResults = new InterestingResults(); private final InterestingResults interestingResults = new InterestingResults();
private final long datasourceObjId;
/**
* Constructor
*
* @param skCase Case DB
*
*/
public InterestingHits(SleuthkitCase skCase) { public InterestingHits(SleuthkitCase skCase) {
this(skCase, 0);
}
/**
* Constructor
*
* @param skCase Case DB
* @param objId Object id of the data source
*
*/
public InterestingHits(SleuthkitCase skCase, long objId) {
this.skCase = skCase; this.skCase = skCase;
this.datasourceObjId = objId;
interestingResults.update(); interestingResults.update();
} }
@ -112,6 +132,9 @@ public class InterestingHits implements AutopsyVisitableItem {
+ "attribute_type_id=" + setNameId //NON-NLS + "attribute_type_id=" + setNameId //NON-NLS
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS
if (UserPreferences.groupItemsInTreeByDatasource()) {
query += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
}
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
synchronized (interestingItemsMap) { synchronized (interestingItemsMap) {

View File

@ -44,6 +44,7 @@ import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import static org.sleuthkit.autopsy.datamodel.Bundle.*; import static org.sleuthkit.autopsy.datamodel.Bundle.*;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
@ -73,6 +74,7 @@ public class KeywordHits implements AutopsyVisitableItem {
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final KeywordResults keywordResults; private final KeywordResults keywordResults;
private final long datasourceObjId;
/** /**
* String used in the instance MAP so that exact matches and substring can * String used in the instance MAP so that exact matches and substring can
@ -81,6 +83,7 @@ public class KeywordHits implements AutopsyVisitableItem {
*/ */
private static final String DEFAULT_INSTANCE_NAME = "DEFAULT_INSTANCE_NAME"; private static final String DEFAULT_INSTANCE_NAME = "DEFAULT_INSTANCE_NAME";
/** /**
* query attributes table for the ones that we need for the tree * query attributes table for the ones that we need for the tree
*/ */
@ -101,8 +104,25 @@ public class KeywordHits implements AutopsyVisitableItem {
return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME)); return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME));
} }
public KeywordHits(SleuthkitCase skCase) { /**
* Constructor
*
* @param skCase Case DB
*/
KeywordHits(SleuthkitCase skCase) {
this(skCase, 0);
}
/**
* Constructor
*
* @param skCase Case DB
* @param objId Object id of the data source
*
*/
public KeywordHits(SleuthkitCase skCase, long objId) {
this.skCase = skCase; this.skCase = skCase;
this.datasourceObjId = objId;
keywordResults = new KeywordResults(); keywordResults = new KeywordResults();
} }
@ -300,7 +320,12 @@ public class KeywordHits implements AutopsyVisitableItem {
return; return;
} }
try (CaseDbQuery dbQuery = skCase.executeQuery(KEYWORD_HIT_ATTRIBUTES_QUERY)) { String queryStr = KEYWORD_HIT_ATTRIBUTES_QUERY;
if (UserPreferences.groupItemsInTreeByDatasource()) {
queryStr += " AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId;
}
try (CaseDbQuery dbQuery = skCase.executeQuery(queryStr)) {
ResultSet resultSet = dbQuery.getResultSet(); ResultSet resultSet = dbQuery.getResultSet();
while (resultSet.next()) { while (resultSet.next()) {
long artifactId = resultSet.getLong("artifact_id"); //NON-NLS long artifactId = resultSet.getLong("artifact_id"); //NON-NLS

View File

@ -26,11 +26,17 @@ import org.sleuthkit.datamodel.SleuthkitCase;
public class Results implements AutopsyVisitableItem { public class Results implements AutopsyVisitableItem {
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final long datasourceObjId;
public Results(SleuthkitCase skCase) { public Results(SleuthkitCase skCase) {
this.skCase = skCase; this(skCase, 0);
} }
public Results(SleuthkitCase skCase, long dsObjId) {
this.skCase = skCase;
this.datasourceObjId = dsObjId;
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> visitor) { public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
@ -39,4 +45,8 @@ public class Results implements AutopsyVisitableItem {
public SleuthkitCase getSleuthkitCase() { public SleuthkitCase getSleuthkitCase() {
return skCase; return skCase;
} }
long filteringDataSourceObjId() {
return datasourceObjId;
}
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2016 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -33,17 +33,22 @@ public class ResultsNode extends DisplayableItemNode {
@NbBundle.Messages("ResultsNode.name.text=Results") @NbBundle.Messages("ResultsNode.name.text=Results")
public static final String NAME = Bundle.ResultsNode_name_text(); public static final String NAME = Bundle.ResultsNode_name_text();
public ResultsNode(SleuthkitCase sleuthkitCase) { public ResultsNode(SleuthkitCase sleuthkitCase) {
super(new RootContentChildren(Arrays.asList( this(sleuthkitCase, 0);
new ExtractedContent(sleuthkitCase), }
new KeywordHits(sleuthkitCase),
new HashsetHits(sleuthkitCase), public ResultsNode(SleuthkitCase sleuthkitCase, long dsObjId) {
new EmailExtracted(sleuthkitCase), super(
new InterestingHits(sleuthkitCase),
new Accounts(sleuthkitCase) new RootContentChildren(Arrays.asList(
)), Lookups.singleton(NAME)); new ExtractedContent(sleuthkitCase, dsObjId ),
new KeywordHits(sleuthkitCase, dsObjId),
new HashsetHits(sleuthkitCase, dsObjId),
new EmailExtracted(sleuthkitCase, dsObjId),
new InterestingHits(sleuthkitCase, dsObjId ),
new Accounts(sleuthkitCase, dsObjId) )
),
Lookups.singleton(NAME));
setName(NAME); setName(NAME);
setDisplayName(NAME); setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png"); //NON-NLS

View File

@ -36,6 +36,7 @@ import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardArtifactTag;
@ -57,6 +58,20 @@ public class Tags implements AutopsyVisitableItem {
private final String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text"); private final String DISPLAY_NAME = NbBundle.getMessage(RootNode.class, "TagsNode.displayName.text");
private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS private final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; //NON-NLS
private final long datasourceObjId;
Tags() {
this(0);
}
Tags(long dsObjId) {
this.datasourceObjId = dsObjId;
}
long filteringDataSourceObjId() {
return this.datasourceObjId;
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> visitor) { public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
@ -83,11 +98,13 @@ public class Tags implements AutopsyVisitableItem {
*/ */
public class RootNode extends DisplayableItemNode { public class RootNode extends DisplayableItemNode {
public RootNode() {
super(Children.create(new TagNameNodeFactory(), true), Lookups.singleton(DISPLAY_NAME)); public RootNode(long objId) {
super(Children.create(new TagNameNodeFactory(objId), true), Lookups.singleton(DISPLAY_NAME));
super.setName(DISPLAY_NAME); super.setName(DISPLAY_NAME);
super.setDisplayName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME);
this.setIconBaseWithExtension(ICON_PATH); this.setIconBaseWithExtension(ICON_PATH);
} }
@Override @Override
@ -121,6 +138,8 @@ public class Tags implements AutopsyVisitableItem {
private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer { private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer {
private final long datasourceObjId;
private final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED, private final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED, Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED,
Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_ADDED,
@ -176,6 +195,15 @@ public class Tags implements AutopsyVisitableItem {
} }
}; };
/**
* Constructor
* @param objId data source object id
*/
TagNameNodeFactory(long objId) {
this.datasourceObjId = objId;
}
@Override @Override
protected void addNotify() { protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(pcl); IngestManager.getInstance().addIngestJobEventListener(pcl);
@ -196,7 +224,11 @@ public class Tags implements AutopsyVisitableItem {
@Override @Override
protected boolean createKeys(List<TagName> keys) { protected boolean createKeys(List<TagName> keys) {
try { try {
List<TagName> tagNamesInUse = Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse();
List<TagName> tagNamesInUse = UserPreferences.groupItemsInTreeByDatasource() ?
Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse(datasourceObjId) :
Case.getCurrentCaseThrows().getServices().getTagsManager().getTagNamesInUse()
;
Collections.sort(tagNamesInUse); Collections.sort(tagNamesInUse);
keys.addAll(tagNamesInUse); keys.addAll(tagNamesInUse);
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
@ -244,8 +276,15 @@ public class Tags implements AutopsyVisitableItem {
long tagsCount = 0; long tagsCount = 0;
try { try {
TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager(); TagsManager tm = Case.getCurrentCaseThrows().getServices().getTagsManager();
tagsCount = tm.getContentTagsCountByTagName(tagName); if (UserPreferences.groupItemsInTreeByDatasource()) {
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName); tagsCount = tm.getContentTagsCountByTagName(tagName, datasourceObjId);
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId);
}
else {
tagsCount = tm.getContentTagsCountByTagName(tagName);
tagsCount += tm.getBlackboardArtifactTagsCountByTagName(tagName);
}
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
} }
@ -348,7 +387,9 @@ public class Tags implements AutopsyVisitableItem {
private void updateDisplayName() { private void updateDisplayName() {
long tagsCount = 0; long tagsCount = 0;
try { try {
tagsCount = Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName); tagsCount = UserPreferences.groupItemsInTreeByDatasource() ?
Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName, datasourceObjId) :
Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
} }
@ -403,7 +444,11 @@ public class Tags implements AutopsyVisitableItem {
protected boolean createKeys(List<ContentTag> keys) { protected boolean createKeys(List<ContentTag> keys) {
// Use the content tags bearing the specified tag name as the keys. // Use the content tags bearing the specified tag name as the keys.
try { try {
keys.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName)); List<ContentTag> contentTags = UserPreferences.groupItemsInTreeByDatasource() ?
Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName, datasourceObjId) :
Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByTagName(tagName);
keys.addAll(contentTags);
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS Logger.getLogger(ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
} }
@ -447,7 +492,9 @@ public class Tags implements AutopsyVisitableItem {
private void updateDisplayName() { private void updateDisplayName() {
long tagsCount = 0; long tagsCount = 0;
try { try {
tagsCount = Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); tagsCount = UserPreferences.groupItemsInTreeByDatasource() ?
Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName, datasourceObjId) :
Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); //NON-NLS
} }
@ -502,7 +549,10 @@ public class Tags implements AutopsyVisitableItem {
protected boolean createKeys(List<BlackboardArtifactTag> keys) { protected boolean createKeys(List<BlackboardArtifactTag> keys) {
try { try {
// Use the blackboard artifact tags bearing the specified tag name as the keys. // Use the blackboard artifact tags bearing the specified tag name as the keys.
keys.addAll(Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName)); List<BlackboardArtifactTag> artifactTags = UserPreferences.groupItemsInTreeByDatasource() ?
Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, datasourceObjId) :
Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName);
keys.addAll(artifactTags);
} catch (TskCoreException | NoCurrentCaseException ex) { } catch (TskCoreException | NoCurrentCaseException ex) {
Logger.getLogger(BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS Logger.getLogger(BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
} }

View File

@ -26,11 +26,21 @@ import org.sleuthkit.datamodel.SleuthkitCase;
public class Views implements AutopsyVisitableItem { public class Views implements AutopsyVisitableItem {
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final long datasourceObjId;
public Views(SleuthkitCase skCase) { public Views(SleuthkitCase skCase) {
this.skCase = skCase; this(skCase, 0);
} }
public Views(SleuthkitCase skCase, long dsObjId) {
this.skCase = skCase;
this.datasourceObjId = dsObjId;
}
long filteringDataSourceObjId() {
return this.datasourceObjId;
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> visitor) { public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2014 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -34,19 +34,28 @@ public class ViewsNode extends DisplayableItemNode {
public static final String NAME = NbBundle.getMessage(ViewsNode.class, "ViewsNode.name.text"); public static final String NAME = NbBundle.getMessage(ViewsNode.class, "ViewsNode.name.text");
public ViewsNode(SleuthkitCase sleuthkitCase) { public ViewsNode(SleuthkitCase sleuthkitCase) {
super(new RootContentChildren(Arrays.asList( this(sleuthkitCase, 0);
new FileTypes(sleuthkitCase), }
// June '15: Recent Files was removed because it was not useful w/out filtering
// add it back in if we can filter the results to a more managable size. public ViewsNode(SleuthkitCase sleuthkitCase, long dsObjId) {
// new RecentFiles(sleuthkitCase),
new DeletedContent(sleuthkitCase), super(
new FileSize(sleuthkitCase))), new RootContentChildren(Arrays.asList(
Lookups.singleton(NAME)); new FileTypes(sleuthkitCase, dsObjId),
// June '15: Recent Files was removed because it was not useful w/out filtering
// add it back in if we can filter the results to a more managable size.
// new RecentFiles(sleuthkitCase),
new DeletedContent(sleuthkitCase, dsObjId),
new FileSize(sleuthkitCase, dsObjId))
),
Lookups.singleton(NAME)
);
setName(NAME); setName(NAME);
setDisplayName(NAME); setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png"); //NON-NLS this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png"); //NON-NLS
} }
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return false; return false;

View File

@ -58,6 +58,7 @@ import org.openide.util.Utilities;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor; import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor;
@ -94,6 +95,8 @@ final public class Accounts implements AutopsyVisitableItem {
final public static String NAME = Bundle.AccountsRootNode_name(); final public static String NAME = Bundle.AccountsRootNode_name();
private SleuthkitCase skCase; private SleuthkitCase skCase;
private final long datasourceObjId;
private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus"); private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus");
/* Should rejected accounts be shown in the accounts section of the tree. */ /* Should rejected accounts be shown in the accounts section of the tree. */
@ -108,12 +111,24 @@ final public class Accounts implements AutopsyVisitableItem {
* @param skCase The SleuthkitCase object to use for db queries. * @param skCase The SleuthkitCase object to use for db queries.
*/ */
public Accounts(SleuthkitCase skCase) { public Accounts(SleuthkitCase skCase) {
this(skCase, 0);
}
/**
* Constructor
*
* @param skCase The SleuthkitCase object to use for db queries.
* @param objId Object id of the data source
*/
public Accounts(SleuthkitCase skCase, long objId) {
this.skCase = skCase; this.skCase = skCase;
this.datasourceObjId = objId;
this.rejectActionInstance = new RejectAccounts(); this.rejectActionInstance = new RejectAccounts();
this.approveActionInstance = new ApproveAccounts(); this.approveActionInstance = new ApproveAccounts();
} }
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> visitor) { public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
@ -130,6 +145,18 @@ final public class Accounts implements AutopsyVisitableItem {
return showRejected ? " " : " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() + " "; //NON-NLS return showRejected ? " " : " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() + " "; //NON-NLS
} }
/**
* Returns the clause to filter artifacts by data source.
*
* @return A clause that will or will not filter artifacts by datasource
* based on the UserPreferences groupItemsInTreeByDatasource setting
*/
private String getFilterByDataSourceClause() {
return (UserPreferences.groupItemsInTreeByDatasource()) ?
" AND blackboard_artifacts.data_source_obj_id = " + datasourceObjId + " "
: " ";
}
/** /**
* Gets a new Action that when invoked toggles showing rejected artifacts on * Gets a new Action that when invoked toggles showing rejected artifacts on
* or off. * or off.
@ -291,10 +318,14 @@ final public class Accounts implements AutopsyVisitableItem {
@Override @Override
protected boolean createKeys(List<String> list) { protected boolean createKeys(List<String> list) {
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery( String accountTypesInUseQuery =
"SELECT DISTINCT blackboard_attributes.value_text as account_type " "SELECT DISTINCT blackboard_attributes.value_text as account_type "
+ " FROM blackboard_attributes " + " FROM blackboard_artifacts " //NON-NLS
+ " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()); + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
+ " WHERE blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID()
+ getFilterByDataSourceClause();
try (SleuthkitCase.CaseDbQuery executeQuery = skCase.executeQuery(accountTypesInUseQuery );
ResultSet resultSet = executeQuery.getResultSet()) { ResultSet resultSet = executeQuery.getResultSet()) {
while (resultSet.next()) { while (resultSet.next()) {
String accountType = resultSet.getString("account_type"); String accountType = resultSet.getString("account_type");
@ -429,6 +460,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
+ " AND blackboard_attributes.value_text = '" + accountType.getTypeName() + "'" //NON-NLS + " AND blackboard_attributes.value_text = '" + accountType.getTypeName() + "'" //NON-NLS
+ getFilterByDataSourceClause()
+ getRejectedArtifactFilterClause(); //NON-NLS + getRejectedArtifactFilterClause(); //NON-NLS
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
ResultSet rs = results.getResultSet();) { ResultSet rs = results.getResultSet();) {
@ -739,6 +771,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ getFilterByDataSourceClause()
+ getRejectedArtifactFilterClause() + getRejectedArtifactFilterClause()
+ " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
+ " ORDER BY hits DESC "; //NON-NLS + " ORDER BY hits DESC "; //NON-NLS
@ -807,6 +840,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS + " AND account_type.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE.getTypeID() //NON-NLS
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS + " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.getTypeName() + "'" //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ getFilterByDataSourceClause()
+ getRejectedArtifactFilterClause() + getRejectedArtifactFilterClause()
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo"; + " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
@ -943,6 +977,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
+ getFilterByDataSourceClause()
+ getRejectedArtifactFilterClause() + getRejectedArtifactFilterClause()
+ " GROUP BY BIN " //NON-NLS + " GROUP BY BIN " //NON-NLS
+ " ORDER BY BIN "; //NON-NLS + " ORDER BY BIN "; //NON-NLS
@ -1009,6 +1044,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
+ getFilterByDataSourceClause()
+ getRejectedArtifactFilterClause(); //NON-NLS + getRejectedArtifactFilterClause(); //NON-NLS
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
ResultSet resultSet = results.getResultSet();) { ResultSet resultSet = results.getResultSet();) {
@ -1304,6 +1340,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS + " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
+ getFilterByDataSourceClause()
+ getRejectedArtifactFilterClause() + getRejectedArtifactFilterClause()
+ " ORDER BY blackboard_attributes.value_text"; //NON-NLS + " ORDER BY blackboard_attributes.value_text"; //NON-NLS
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
@ -1375,6 +1412,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS + " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
+ getFilterByDataSourceClause()
+ getRejectedArtifactFilterClause(); + getRejectedArtifactFilterClause();
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
ResultSet resultSet = results.getResultSet();) { ResultSet resultSet = results.getResultSet();) {

View File

@ -119,3 +119,4 @@ AddExternalViewerRulePanel.browseButton.text=Browse
AddExternalViewerRulePanel.exePathTextField.text= AddExternalViewerRulePanel.exePathTextField.text=
AddExternalViewerRulePanel.exePathLabel.text=Path of the program to use for files with this type or extension AddExternalViewerRulePanel.exePathLabel.text=Path of the program to use for files with this type or extension
AddExternalViewerRulePanel.extRadioButton.text=Extension AddExternalViewerRulePanel.extRadioButton.text=Extension
DirectoryTreeTopComponent.groupByDatasourceCheckBox.text=Group by Data Source

View File

@ -16,14 +16,17 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="treeView" alignment="0" pref="262" max="32767" attributes="0"/> <Component id="treeView" alignment="0" max="32767" attributes="0"/>
<Group type="102" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="backButton" min="-2" pref="23" max="-2" attributes="0"/> <Component id="backButton" min="-2" pref="23" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="forwardButton" min="-2" pref="23" max="-2" attributes="0"/> <Component id="forwardButton" min="-2" pref="23" max="-2" attributes="0"/>
<EmptySpace pref="46" max="32767" attributes="0"/> <EmptySpace pref="65" max="32767" attributes="0"/>
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
@ -31,14 +34,23 @@
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0"> <Group type="102" attributes="0">
<Component id="forwardButton" min="-2" pref="26" max="-2" attributes="1"/> <EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Component id="backButton" min="-2" pref="26" max="-2" attributes="1"/> <Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="forwardButton" min="-2" pref="26" max="-2" attributes="1"/>
<Component id="backButton" min="-2" pref="26" max="-2" attributes="1"/>
</Group>
</Group>
</Group> </Group>
<EmptySpace min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="treeView" pref="854" max="32767" attributes="0"/> <Component id="treeView" pref="838" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
@ -130,5 +142,15 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="groupByDatasourceCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.groupByDatasourceCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="groupByDatasourceCheckBoxActionPerformed"/>
</Events>
</Component>
</SubComponents> </SubComponents>
</Form> </Form>

View File

@ -30,6 +30,7 @@ import java.util.EnumSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.prefs.PreferenceChangeEvent; import java.util.prefs.PreferenceChangeEvent;
@ -64,8 +65,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.CreditCards; import org.sleuthkit.autopsy.datamodel.CreditCards;
import org.sleuthkit.autopsy.datamodel.DataSources;
import org.sleuthkit.autopsy.datamodel.DataSourcesNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.datamodel.EmailExtracted; import org.sleuthkit.autopsy.datamodel.EmailExtracted;
import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.datamodel.EmptyNode;
@ -73,12 +72,8 @@ import org.sleuthkit.autopsy.datamodel.ExtractedContent;
import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType; import org.sleuthkit.autopsy.datamodel.FileTypesByMimeType;
import org.sleuthkit.autopsy.datamodel.InterestingHits; import org.sleuthkit.autopsy.datamodel.InterestingHits;
import org.sleuthkit.autopsy.datamodel.KeywordHits; import org.sleuthkit.autopsy.datamodel.KeywordHits;
import org.sleuthkit.autopsy.datamodel.Reports;
import org.sleuthkit.autopsy.datamodel.Results;
import org.sleuthkit.autopsy.datamodel.ResultsNode; import org.sleuthkit.autopsy.datamodel.ResultsNode;
import org.sleuthkit.autopsy.datamodel.RootContentChildren; import org.sleuthkit.autopsy.datamodel.AutopsyTreeChildrenFactory;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.Views;
import org.sleuthkit.autopsy.datamodel.ViewsNode; import org.sleuthkit.autopsy.datamodel.ViewsNode;
import org.sleuthkit.autopsy.datamodel.accounts.Accounts; import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
import org.sleuthkit.autopsy.datamodel.accounts.BINRange; import org.sleuthkit.autopsy.datamodel.accounts.BINRange;
@ -107,7 +102,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
private final LinkedList<String[]> forwardList; private final LinkedList<String[]> forwardList;
private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS private static final String PREFERRED_ID = "DirectoryTreeTopComponent"; //NON-NLS
private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName()); private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
private RootContentChildren contentChildren; private AutopsyTreeChildrenFactory autopsyTreeChildrenFactory;
private Children autopsyTreeChildren;
/** /**
* the constructor * the constructor
@ -130,6 +126,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
this.forwardList = new LinkedList<>(); this.forwardList = new LinkedList<>();
backButton.setEnabled(false); backButton.setEnabled(false);
forwardButton.setEnabled(false); forwardButton.setEnabled(false);
groupByDatasourceCheckBox.setSelected(UserPreferences.groupItemsInTreeByDatasource());
} }
/** /**
@ -142,6 +140,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
switch (evt.getKey()) { switch (evt.getKey()) {
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE: case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE: case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.GROUP_ITEMS_IN_TREE_BY_DATASOURCE:
refreshContentTreeSafe(); refreshContentTreeSafe();
break; break;
case UserPreferences.HIDE_KNOWN_FILES_IN_VIEWS_TREE: case UserPreferences.HIDE_KNOWN_FILES_IN_VIEWS_TREE:
@ -182,6 +181,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
backButton = new javax.swing.JButton(); backButton = new javax.swing.JButton();
forwardButton = new javax.swing.JButton(); forwardButton = new javax.swing.JButton();
showRejectedCheckBox = new javax.swing.JCheckBox(); showRejectedCheckBox = new javax.swing.JCheckBox();
groupByDatasourceCheckBox = new javax.swing.JCheckBox();
treeView.setBorder(null); treeView.setBorder(null);
@ -219,30 +219,45 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
org.openide.awt.Mnemonics.setLocalizedText(showRejectedCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showRejectedCheckBox.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(showRejectedCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.showRejectedCheckBox.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(groupByDatasourceCheckBox, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.groupByDatasourceCheckBox.text")); // NOI18N
groupByDatasourceCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
groupByDatasourceCheckBoxActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE) .addComponent(treeView)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(5, 5, 5) .addContainerGap()
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0) .addGap(0, 0, 0)
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 46, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 65, Short.MAX_VALUE)
.addComponent(showRejectedCheckBox) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(showRejectedCheckBox)
.addComponent(groupByDatasourceCheckBox))
.addContainerGap()) .addContainerGap())
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(5, 5, 5) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup()
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(5, 5, 5)
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(showRejectedCheckBox)
.addComponent(showRejectedCheckBox)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(groupByDatasourceCheckBox))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 854, Short.MAX_VALUE) .addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 838, Short.MAX_VALUE)
.addGap(0, 0, 0)) .addGap(0, 0, 0))
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@ -296,9 +311,14 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
this.setCursor(null); this.setCursor(null);
}//GEN-LAST:event_forwardButtonActionPerformed }//GEN-LAST:event_forwardButtonActionPerformed
private void groupByDatasourceCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_groupByDatasourceCheckBoxActionPerformed
UserPreferences.setGroupItemsInTreeByDatasource(this.groupByDatasourceCheckBox.isSelected());
}//GEN-LAST:event_groupByDatasourceCheckBoxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton backButton; private javax.swing.JButton backButton;
private javax.swing.JButton forwardButton; private javax.swing.JButton forwardButton;
private javax.swing.JCheckBox groupByDatasourceCheckBox;
private javax.swing.JCheckBox showRejectedCheckBox; private javax.swing.JCheckBox showRejectedCheckBox;
private javax.swing.JScrollPane treeView; private javax.swing.JScrollPane treeView;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
@ -376,13 +396,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
} else { } else {
// if there's at least one image, load the image and open the top component // if there's at least one image, load the image and open the top component
final SleuthkitCase tskCase = currentCase.getSleuthkitCase(); final SleuthkitCase tskCase = currentCase.getSleuthkitCase();
contentChildren = new RootContentChildren(Arrays.asList(
new DataSources(), autopsyTreeChildrenFactory = new AutopsyTreeChildrenFactory(tskCase);
new Views(tskCase), autopsyTreeChildren = Children.create(autopsyTreeChildrenFactory, true);
new Results(tskCase), Node root = new AbstractNode(autopsyTreeChildren) {
new Tags(),
new Reports()));
Node root = new AbstractNode(contentChildren) {
//JIRA-2807: What is the point of these overrides? //JIRA-2807: What is the point of these overrides?
/** /**
* to override the right click action in the white blank space * to override the right click action in the white blank space
@ -422,17 +439,23 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
TreeView tree = getTree(); TreeView tree = getTree();
Node results = rootChildren.findChild(ResultsNode.NAME); Node results = rootChildren.findChild(ResultsNode.NAME);
tree.expandNode(results); if (!Objects.isNull(results)) {
Children resultsChildren = results.getChildren(); tree.expandNode(results);
Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode); Children resultsChildren = results.getChildren();
Arrays.stream(resultsChildren.getNodes()).forEach(tree::expandNode);
Accounts accounts = resultsChildren.findChild(Accounts.NAME).getLookup().lookup(Accounts.class); Accounts accounts = resultsChildren.findChild(Accounts.NAME).getLookup().lookup(Accounts.class);
showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction()); if (!Objects.isNull(accounts)) {
showRejectedCheckBox.setSelected(false); showRejectedCheckBox.setAction(accounts.newToggleShowRejectedAction());
showRejectedCheckBox.setSelected(false);
}
}
Node views = rootChildren.findChild(ViewsNode.NAME); Node views = rootChildren.findChild(ViewsNode.NAME);
Arrays.stream(views.getChildren().getNodes()).forEach(tree::expandNode); if (!Objects.isNull(views)) {
tree.collapseNode(views); Arrays.stream(views.getChildren().getNodes()).forEach(tree::expandNode);
tree.collapseNode(views);
}
/* /*
* JIRA-2806: What is this supposed to do? Right now it selects * JIRA-2806: What is this supposed to do? Right now it selects
* the data sources node, but the comment seems to indicate * the data sources node, but the comment seems to indicate
@ -464,7 +487,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
// of changing the selected node fires a handler that tries to make // of changing the selected node fires a handler that tries to make
// dataResult active) // dataResult active)
try { try {
em.setSelectedNodes(get()); Node[] selections = get();
if (selections != null && selections.length > 0){
em.setSelectedNodes(selections);
}
} catch (PropertyVetoException ex) { } catch (PropertyVetoException ex) {
LOGGER.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS LOGGER.log(Level.SEVERE, "Error setting default selected node.", ex); //NON-NLS
} catch (InterruptedException | ExecutionException ex) { } catch (InterruptedException | ExecutionException ex) {
@ -486,7 +512,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
@Override @Override
public void componentClosed() { public void componentClosed() {
//@@@ push the selection node to null? //@@@ push the selection node to null?
contentChildren = null; autopsyTreeChildren = null;
} }
void writeProperties(java.util.Properties p) { void writeProperties(java.util.Properties p) {
@ -729,7 +755,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
*/ */
String[] currentLast = backList.peekLast(); String[] currentLast = backList.peekLast();
String lastNodeName = null; String lastNodeName = null;
if (currentLast != null) { if (currentLast != null && currentLast.length > 0) {
lastNodeName = currentLast[currentLast.length - 1]; lastNodeName = currentLast[currentLast.length - 1];
} }
@ -773,27 +799,56 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
* Refresh the content node part of the dir tree safely in the EDT thread * Refresh the content node part of the dir tree safely in the EDT thread
*/ */
public void refreshContentTreeSafe() { public void refreshContentTreeSafe() {
SwingUtilities.invokeLater(this::refreshDataSourceTree); SwingUtilities.invokeLater(this::rebuildTree);
} }
/** /**
* Refreshes changed content nodes * Rebuilds the directory tree
*/ */
private void refreshDataSourceTree() { private void rebuildTree() {
Node selectedNode = getSelectedNode();
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
Children rootChildren = em.getRootContext().getChildren();
Node dataSourcesFilterNode = rootChildren.findChild(DataSourcesNode.NAME);
if (dataSourcesFilterNode == null) {
LOGGER.log(Level.SEVERE, "Cannot find data sources filter node, won't refresh the content tree"); //NON-NLS
return;
}
Node dataSourcesNode = ((DirectoryTreeFilterNode) dataSourcesFilterNode).getOriginal();
DataSourcesNode.DataSourcesNodeChildren contentRootChildren = (DataSourcesNode.DataSourcesNodeChildren) dataSourcesNode.getChildren();
contentRootChildren.refreshContentKeys();
setSelectedNode(selectedPath, DataSourcesNode.NAME);
}
// refresh all children of the root.
autopsyTreeChildrenFactory.refreshChildren();
// Select the first node and reset the selection history
// This should happen on the EDT once the tree has been rebuilt.
// hence the SwingWorker that does this in the done() method
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
return null;
}
@Override
protected void done() {
super.done();
try {
get();
selectFirstChildNode();
resetHistory();
} catch (InterruptedException | ExecutionException ex) {
LOGGER.log(Level.SEVERE, "Error selecting tree node.", ex); //NON-NLS
} //NON-NLS
}
}.execute();
}
/**
* Selects the first node in the tree.
*
*/
private void selectFirstChildNode () {
Children rootChildren = em.getRootContext().getChildren();
if (rootChildren.getNodesCount() > 0) {
Node firstNode = rootChildren.getNodeAt(0);
if (firstNode != null) {
final String[] selectedPath = NodeOp.createPath(firstNode, em.getRootContext());
setSelectedNode(selectedPath, null);
}
}
}
/** /**
* Set the selected node using a path to a previously selected node. * Set the selected node using a path to a previously selected node.
* *

View File

@ -24,6 +24,7 @@ import java.beans.PropertyVetoException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
@ -33,6 +34,8 @@ import org.openide.explorer.view.TreeView;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
@ -44,9 +47,12 @@ import org.sleuthkit.autopsy.datamodel.RootContentChildren;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.VolumeSystem; import org.sleuthkit.datamodel.VolumeSystem;
/** /**
@ -122,7 +128,9 @@ public class ViewContextAction extends AbstractAction {
@Override @Override
@Messages({ @Messages({
"ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.", "ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.",
"ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.",}) "ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.",
"ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree."
})
public void actionPerformed(ActionEvent event) { public void actionPerformed(ActionEvent event) {
EventQueue.invokeLater(() -> { EventQueue.invokeLater(() -> {
/* /*
@ -130,7 +138,40 @@ public class ViewContextAction extends AbstractAction {
*/ */
DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance();
ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager();
Node parentTreeViewNode = treeViewExplorerMgr.getRootContext().getChildren().findChild(DataSourcesNode.NAME);
Node parentTreeViewNode;
if (UserPreferences.groupItemsInTreeByDatasource()) { // 'Group by Data Source' view
SleuthkitCase skCase;
String dsname;
try {
// get the objid/name of the datasource of the selected content.
skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
long contentDSObjid = content.getDataSource().getId();
DataSource datasource = skCase.getDataSource(contentDSObjid);
dsname = datasource.getName();
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
Node datasourceGroupingNode = rootChildren.findChild(dsname);
if (! Objects.isNull(datasourceGroupingNode) ) {
Children dsChildren = datasourceGroupingNode.getChildren();
parentTreeViewNode = dsChildren.findChild(DataSourcesNode.NAME);
}
else {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree."); //NON-NLS
return;
}
} catch (NoCurrentCaseException| TskDataException | TskCoreException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree.", ex); //NON-NLS
return;
}
} else { // Classic view
// Start the search at the DataSourcesNode
parentTreeViewNode = treeViewExplorerMgr.getRootContext().getChildren().findChild(DataSourcesNode.NAME);
}
/* /*
* Get the parent content for the content to be selected in the * Get the parent content for the content to be selected in the
* results view. If the parent content is null, then the specified * results view. If the parent content is null, then the specified

View File

@ -46,7 +46,7 @@ import static junit.framework.Assert.assertTrue;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
/** /**
* * Functional tests for the Central Repository data model.
*/ */
public class CentralRepoDatamodelTest extends TestCase { public class CentralRepoDatamodelTest extends TestCase {
@ -115,7 +115,7 @@ public class CentralRepoDatamodelTest extends TestCase {
EamDbUtil.setUseCentralRepo(true); EamDbUtil.setUseCentralRepo(true);
EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.SQLITE.name()); EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.SQLITE.name());
EamDbPlatformEnum.saveSelectedPlatform(); EamDbPlatformEnum.saveSelectedPlatform();
} catch (Exception ex) { } catch (EamDbException ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
Assert.fail(ex); Assert.fail(ex);
} }
@ -2554,7 +2554,7 @@ public class CentralRepoDatamodelTest extends TestCase {
// This seems to help in allowing the Autopsy case to be deleted // This seems to help in allowing the Autopsy case to be deleted
try { try {
Thread.sleep(2000); Thread.sleep(2000);
} catch (Exception ex) { } catch (InterruptedException ex) {
} }
} catch (CaseActionException ex) { } catch (CaseActionException ex) {

View File

@ -1,5 +1,4 @@
/* /*
*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2018 Basis Technology Corp. * Copyright 2018 Basis Technology Corp.
@ -84,20 +83,20 @@ class IntraCaseUtils {
static final String PDF = "adsf.pdf"; //not a typo - it appears this way in the test image static final String PDF = "adsf.pdf"; //not a typo - it appears this way in the test image
static final String EMPTY = "file.dat"; static final String EMPTY = "file.dat";
static final String SET1 = "commonfiles_image1_v1.vhd"; static final String SET1 = "CommonFiles_img1_v1.vhd";
static final String SET2 = "commonfiles_image2_v1.vhd"; static final String SET2 = "CommonFiles_img2_v1.vhd";
static final String SET3 = "commonfiles_image3_v1.vhd"; static final String SET3 = "CommonFiles_img3_v1.vhd";
static final String SET4 = "commonfiles_image4_v1.vhd"; static final String SET4 = "CommonFiles_img4_v1.vhd";
private final DataSourceLoader dataSourceLoader; private final DataSourceLoader dataSourceLoader;
private final String caseName; private final String caseName;
IntraCaseUtils(NbTestCase nbTestCase, String caseName){ IntraCaseUtils(NbTestCase nbTestCase, String caseName){
imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image1_v1.vhd"); imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), SET1);
imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image2_v1.vhd"); imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), SET2);
imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image3_v1.vhd"); imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), SET3);
imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), "commonfiles_image4_v1.vhd"); imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), SET4);
this.dataSourceLoader = new DataSourceLoader(); this.dataSourceLoader = new DataSourceLoader();

View File

@ -39,11 +39,13 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/**
* Functional tests for embedded files.
*/
public class EmbeddedFileTest extends NbTestCase { public class EmbeddedFileTest extends NbTestCase {
private static final String CASE_NAME = "EmbeddedFileTest"; private static final String CASE_NAME = "EmbeddedFileTest";
private static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), CASE_NAME); private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(), "EmbeddedIM_img1_v1.vhd");
private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(),"embedded.vhd");
public static final String HASH_VALUE = "098f6bcd4621d373cade4e832627b4f6"; public static final String HASH_VALUE = "098f6bcd4621d373cade4e832627b4f6";
private static final int DEEP_FOLDER_COUNT = 25; private static final int DEEP_FOLDER_COUNT = 25;
private Case openCase; private Case openCase;

View File

@ -50,10 +50,13 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
/**
* Functional tests for ingest file filters.
*/
public class IngestFileFiltersTest extends NbTestCase { public class IngestFileFiltersTest extends NbTestCase {
private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(),"filter_test1.img"); private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(),"IngestFilters_img1_v1.img");
private final Path ZIPFILE_PATH = Paths.get(this.getDataDir().toString(), "local_files_test.zip"); private final Path ZIPFILE_PATH = Paths.get(this.getDataDir().toString(), "IngestFilters_local1_v1.zip");
private boolean testSucceeded; private boolean testSucceeded;

View File

@ -47,6 +47,9 @@ import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.Volume;
import org.sleuthkit.datamodel.VolumeSystem; import org.sleuthkit.datamodel.VolumeSystem;
/**
* Functional tests for Encryption Detection.
*/
public class EncryptionDetectionTest extends NbTestCase { public class EncryptionDetectionTest extends NbTestCase {
private static final String BITLOCKER_DETECTION_CASE_NAME = "testBitlockerEncryption"; private static final String BITLOCKER_DETECTION_CASE_NAME = "testBitlockerEncryption";
@ -54,10 +57,10 @@ public class EncryptionDetectionTest extends NbTestCase {
private static final String VERACRYPT_DETECTION_CASE_NAME = "VeraCryptDetectionTest"; private static final String VERACRYPT_DETECTION_CASE_NAME = "VeraCryptDetectionTest";
private static final String SQLCIPHER_DETECTION_CASE_NAME = "SQLCipherDetectionTest"; private static final String SQLCIPHER_DETECTION_CASE_NAME = "SQLCipherDetectionTest";
private final Path BITLOCKER_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "encryption_detection_bitlocker_test.vhd"); private final Path BITLOCKER_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "BitlockerDetection_img1_v1.vhd");
private final Path PASSWORD_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "password_detection_test.img"); private final Path PASSWORD_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "PasswordDetection_img1_v1.img");
private final Path VERACRYPT_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "veracrypt_detection_test.vhd"); private final Path VERACRYPT_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "VeracryptDetection_img1_v1.vhd");
private final Path SQLCIPHER_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "encryption_detection_sqlcipher_test.vhd"); private final Path SQLCIPHER_DETECTION_IMAGE_PATH = Paths.get(this.getDataDir().toString(), "SqlCipherDetection_img1_v1.vhd");
private boolean testSucceeded; private boolean testSucceeded;

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 4.7.0 PROJECT_NUMBER = 4.8.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
@ -1025,7 +1025,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = 4.7.0 HTML_OUTPUT = 4.8.0
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).

View File

@ -38,10 +38,10 @@ PROJECT_NAME = "Autopsy"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 4.7.0 PROJECT_NUMBER = 4.8.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears a the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short. # quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Graphical digital forensics platform for The Sleuth Kit and other tools." PROJECT_BRIEF = "Graphical digital forensics platform for The Sleuth Kit and other tools."
@ -1063,7 +1063,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = api-docs/4.7.0/ HTML_OUTPUT = api-docs/4.8.0/
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).

View File

@ -4,10 +4,10 @@ app.title=Autopsy
### lowercase version of above ### lowercase version of above
app.name=${branding.token} app.name=${branding.token}
### if left unset, version will default to today's date ### if left unset, version will default to today's date
app.version=4.7.0 app.version=4.8.0
### build.type must be one of: DEVELOPMENT, RELEASE ### build.type must be one of: DEVELOPMENT, RELEASE
#build.type=RELEASE build.type=RELEASE
build.type=DEVELOPMENT #build.type=DEVELOPMENT
project.org.netbeans.progress=org-netbeans-api-progress project.org.netbeans.progress=org-netbeans-api-progress
project.org.sleuthkit.autopsy.experimental=Experimental project.org.sleuthkit.autopsy.experimental=Experimental