mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
Merge branch 'develop' of https://github.com/sleuthkit/autopsy into image-gallery-db-migration
# Conflicts: # ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java
This commit is contained in:
commit
57eff3df95
@ -64,14 +64,14 @@ public final class ReplaceBlackboardArtifactTagAction extends ReplaceTagAction<B
|
|||||||
*
|
*
|
||||||
* @param oldArtifactTag tag to be replaced
|
* @param oldArtifactTag tag to be replaced
|
||||||
* @param newTagName name of the tag to replace with
|
* @param newTagName name of the tag to replace with
|
||||||
* @param comment the comment for the tag use an empty string for no comment
|
* @param newComment the newComment for the tag use an empty string for no newComment
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"# {0} - old tag name",
|
"# {0} - old tag name",
|
||||||
"# {1} - artifactID",
|
"# {1} - artifactID",
|
||||||
"ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}."})
|
"ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}."})
|
||||||
@Override
|
@Override
|
||||||
protected void replaceTag( BlackboardArtifactTag oldArtifactTag, TagName newTagName, String comment) {
|
protected void replaceTag( BlackboardArtifactTag oldArtifactTag, TagName newTagName, String newComment) {
|
||||||
new SwingWorker<Void, Void>() {
|
new SwingWorker<Void, Void>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -91,7 +91,7 @@ public final class ReplaceBlackboardArtifactTagAction extends ReplaceTagAction<B
|
|||||||
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldArtifactTag.getName().getDisplayName(), newTagName.getDisplayName(), oldArtifactTag.getContent().getName()}); //NON-NLS
|
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldArtifactTag.getName().getDisplayName(), newTagName.getDisplayName(), oldArtifactTag.getContent().getName()}); //NON-NLS
|
||||||
|
|
||||||
tagsManager.deleteBlackboardArtifactTag(oldArtifactTag);
|
tagsManager.deleteBlackboardArtifactTag(oldArtifactTag);
|
||||||
tagsManager.addBlackboardArtifactTag(oldArtifactTag.getArtifact(), newTagName, comment);
|
tagsManager.addBlackboardArtifactTag(oldArtifactTag.getArtifact(), newTagName, newComment);
|
||||||
|
|
||||||
} catch (TskCoreException tskCoreException) {
|
} catch (TskCoreException tskCoreException) {
|
||||||
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
||||||
|
@ -64,7 +64,7 @@ public final class ReplaceContentTagAction extends ReplaceTagAction<ContentTag>
|
|||||||
"# {1} - content obj id",
|
"# {1} - content obj id",
|
||||||
"ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}."})
|
"ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}."})
|
||||||
@Override
|
@Override
|
||||||
protected void replaceTag(ContentTag oldTag, TagName newTagName, String comment) {
|
protected void replaceTag(ContentTag oldTag, TagName newTagName, String newComment) {
|
||||||
new SwingWorker<Void, Void>() {
|
new SwingWorker<Void, Void>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -84,7 +84,7 @@ public final class ReplaceContentTagAction extends ReplaceTagAction<ContentTag>
|
|||||||
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldTag.getName().getDisplayName(), newTagName.getDisplayName(), oldTag.getContent().getName()}); //NON-NLS
|
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldTag.getName().getDisplayName(), newTagName.getDisplayName(), oldTag.getContent().getName()}); //NON-NLS
|
||||||
|
|
||||||
tagsManager.deleteContentTag(oldTag);
|
tagsManager.deleteContentTag(oldTag);
|
||||||
tagsManager.addContentTag(oldTag.getContent(), newTagName, comment);
|
tagsManager.addContentTag(oldTag.getContent(), newTagName, newComment);
|
||||||
|
|
||||||
} catch (TskCoreException tskCoreException) {
|
} catch (TskCoreException tskCoreException) {
|
||||||
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
||||||
|
@ -141,7 +141,7 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
|||||||
// Add action to replace the tag
|
// Add action to replace the tag
|
||||||
tagNameItem.addActionListener((ActionEvent event) -> {
|
tagNameItem.addActionListener((ActionEvent event) -> {
|
||||||
selectedTags.forEach((oldtag) -> {
|
selectedTags.forEach((oldtag) -> {
|
||||||
replaceTag(oldtag, entry.getValue(), "");
|
replaceTag(oldtag, entry.getValue(), oldtag.getComment());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
|||||||
TagName newTagName = GetTagNameDialog.doDialog();
|
TagName newTagName = GetTagNameDialog.doDialog();
|
||||||
if (null != newTagName) {
|
if (null != newTagName) {
|
||||||
selectedTags.forEach((oldtag) -> {
|
selectedTags.forEach((oldtag) -> {
|
||||||
replaceTag(oldtag, newTagName, "");
|
replaceTag(oldtag, newTagName, oldtag.getComment());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -129,6 +129,7 @@ public class Case {
|
|||||||
private static final String EXPORT_FOLDER = "Export"; //NON-NLS
|
private static final String EXPORT_FOLDER = "Export"; //NON-NLS
|
||||||
private static final String LOG_FOLDER = "Log"; //NON-NLS
|
private static final String LOG_FOLDER = "Log"; //NON-NLS
|
||||||
private static final String REPORTS_FOLDER = "Reports"; //NON-NLS
|
private static final String REPORTS_FOLDER = "Reports"; //NON-NLS
|
||||||
|
private static final String CONFIG_FOLDER = "Config"; // NON-NLS
|
||||||
private static final String TEMP_FOLDER = "Temp"; //NON-NLS
|
private static final String TEMP_FOLDER = "Temp"; //NON-NLS
|
||||||
private static final String MODULE_FOLDER = "ModuleOutput"; //NON-NLS
|
private static final String MODULE_FOLDER = "ModuleOutput"; //NON-NLS
|
||||||
private static final String CASE_ACTION_THREAD_NAME = "%s-case-action";
|
private static final String CASE_ACTION_THREAD_NAME = "%s-case-action";
|
||||||
@ -1351,6 +1352,16 @@ public class Case {
|
|||||||
return getOrCreateSubdirectory(REPORTS_FOLDER);
|
return getOrCreateSubdirectory(REPORTS_FOLDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the full path to the config directory for this case, creating it if
|
||||||
|
* it does not exist.
|
||||||
|
*
|
||||||
|
* @return The config directory path.
|
||||||
|
*/
|
||||||
|
public String getConfigDirectory() {
|
||||||
|
return getOrCreateSubdirectory(CONFIG_FOLDER);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the full path to the module output directory for this case, creating
|
* Gets the full path to the module output directory for this case, creating
|
||||||
* it if it does not exist.
|
* it if it does not exist.
|
||||||
|
@ -54,7 +54,7 @@ final class TagNameDefinition implements Comparable<TagNameDefinition> {
|
|||||||
private static final List<String> STANDARD_TAG_DISPLAY_NAMES = Arrays.asList(Bundle.TagNameDefinition_predefTagNames_bookmark_text(), Bundle.TagNameDefinition_predefTagNames_followUp_text(),
|
private static final List<String> STANDARD_TAG_DISPLAY_NAMES = Arrays.asList(Bundle.TagNameDefinition_predefTagNames_bookmark_text(), Bundle.TagNameDefinition_predefTagNames_followUp_text(),
|
||||||
Bundle.TagNameDefinition_predefTagNames_notableItem_text(), DhsImageCategory.ONE.getDisplayName(),
|
Bundle.TagNameDefinition_predefTagNames_notableItem_text(), DhsImageCategory.ONE.getDisplayName(),
|
||||||
DhsImageCategory.TWO.getDisplayName(), DhsImageCategory.THREE.getDisplayName(),
|
DhsImageCategory.TWO.getDisplayName(), DhsImageCategory.THREE.getDisplayName(),
|
||||||
DhsImageCategory.FOUR.getDisplayName(), DhsImageCategory.FIVE.getDisplayName());
|
DhsImageCategory.FOUR.getDisplayName(), DhsImageCategory.FIVE.getDisplayName(), DhsImageCategory.ZERO.getDisplayName());
|
||||||
private final String displayName;
|
private final String displayName;
|
||||||
private final String description;
|
private final String description;
|
||||||
private final TagName.HTML_COLOR color;
|
private final TagName.HTML_COLOR color;
|
||||||
|
@ -105,7 +105,7 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction {
|
|||||||
dbManager.updateAttributeInstanceComment(correlationAttribute);
|
dbManager.updateAttributeInstanceComment(correlationAttribute);
|
||||||
}
|
}
|
||||||
} catch (EamDbException ex) {
|
} catch (EamDbException ex) {
|
||||||
logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex);
|
logger.log(Level.SEVERE, "Error adding comment", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return centralRepoCommentDialog.getComment();
|
return centralRepoCommentDialog.getComment();
|
||||||
|
@ -58,6 +58,9 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
protected int bulkArtifactsThreshold;
|
protected int bulkArtifactsThreshold;
|
||||||
private final Map<String, Collection<CorrelationAttribute>> bulkArtifacts;
|
private final Map<String, Collection<CorrelationAttribute>> bulkArtifacts;
|
||||||
|
|
||||||
|
// Maximum length for the value column in the instance tables
|
||||||
|
static final int MAX_VALUE_LENGTH = 128;
|
||||||
|
|
||||||
// number of instances to keep in bulk queue before doing an insert.
|
// number of instances to keep in bulk queue before doing an insert.
|
||||||
// Update Test code if this changes. It's hard coded there.
|
// Update Test code if this changes. It's hard coded there.
|
||||||
static final int DEFAULT_BULK_THRESHHOLD = 1000;
|
static final int DEFAULT_BULK_THRESHHOLD = 1000;
|
||||||
@ -432,7 +435,8 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
if (eamDataSource.getCaseID() == -1) {
|
if (eamDataSource.getCaseID() == -1) {
|
||||||
throw new EamDbException("Case ID is -1");
|
throw new EamDbException("Case ID is -1");
|
||||||
} else if (eamDataSource.getID() != -1) {
|
} else if (eamDataSource.getID() != -1) {
|
||||||
throw new EamDbException("Database ID is already set in object");
|
// This data source is already in the central repo
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
Connection conn = connect();
|
Connection conn = connect();
|
||||||
|
|
||||||
@ -550,6 +554,13 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
if (eamArtifact.getCorrelationValue() == null) {
|
if (eamArtifact.getCorrelationValue() == null) {
|
||||||
throw new EamDbException("Correlation value is null");
|
throw new EamDbException("Correlation value is null");
|
||||||
}
|
}
|
||||||
|
if (eamArtifact.getCorrelationValue().length() >= MAX_VALUE_LENGTH) {
|
||||||
|
throw new EamDbException("Artifact value too long for central repository."
|
||||||
|
+ "\nCorrelationArtifact ID: " + eamArtifact.getID()
|
||||||
|
+ "\nCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
|
||||||
|
+ "\nCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Connection conn = connect();
|
Connection conn = connect();
|
||||||
|
|
||||||
@ -975,27 +986,50 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
if (!eamArtifact.getCorrelationValue().isEmpty()) {
|
if (!eamArtifact.getCorrelationValue().isEmpty()) {
|
||||||
|
|
||||||
if (eamInstance.getCorrelationCase() == null) {
|
if (eamInstance.getCorrelationCase() == null) {
|
||||||
throw new EamDbException("CorrelationAttributeInstance case is null");
|
throw new EamDbException("CorrelationAttributeInstance case is null for: "
|
||||||
|
+ "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
|
||||||
|
+ "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
|
||||||
|
+ "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
|
||||||
}
|
}
|
||||||
if (eamInstance.getCorrelationDataSource() == null) {
|
if (eamInstance.getCorrelationDataSource() == null) {
|
||||||
throw new EamDbException("CorrelationAttributeInstance data source is null");
|
throw new EamDbException("CorrelationAttributeInstance data source is null for: "
|
||||||
|
+ "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
|
||||||
|
+ "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
|
||||||
|
+ "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
|
||||||
}
|
}
|
||||||
if (eamInstance.getKnownStatus() == null) {
|
if (eamInstance.getKnownStatus() == null) {
|
||||||
throw new EamDbException("CorrelationAttributeInstance known status is null");
|
throw new EamDbException("CorrelationAttributeInstance known status is null for: "
|
||||||
|
+ "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
|
||||||
|
+ "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
|
||||||
|
+ "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue()
|
||||||
|
+ "\n\tEam Instance: "
|
||||||
|
+ "\n\t\tCaseId: " + eamInstance.getCorrelationDataSource().getCaseID()
|
||||||
|
+ "\n\t\tDeviceID: " + eamInstance.getCorrelationDataSource().getDeviceID());
|
||||||
}
|
}
|
||||||
|
|
||||||
bulkPs.setString(1, eamInstance.getCorrelationCase().getCaseUUID());
|
if (eamArtifact.getCorrelationValue().length() < MAX_VALUE_LENGTH) {
|
||||||
bulkPs.setString(2, eamInstance.getCorrelationDataSource().getDeviceID());
|
bulkPs.setString(1, eamInstance.getCorrelationCase().getCaseUUID());
|
||||||
bulkPs.setInt(3, eamInstance.getCorrelationDataSource().getCaseID());
|
bulkPs.setString(2, eamInstance.getCorrelationDataSource().getDeviceID());
|
||||||
bulkPs.setString(4, eamArtifact.getCorrelationValue());
|
bulkPs.setInt(3, eamInstance.getCorrelationDataSource().getCaseID());
|
||||||
bulkPs.setString(5, eamInstance.getFilePath());
|
bulkPs.setString(4, eamArtifact.getCorrelationValue());
|
||||||
bulkPs.setByte(6, eamInstance.getKnownStatus().getFileKnownValue());
|
bulkPs.setString(5, eamInstance.getFilePath());
|
||||||
if ("".equals(eamInstance.getComment())) {
|
bulkPs.setByte(6, eamInstance.getKnownStatus().getFileKnownValue());
|
||||||
bulkPs.setNull(7, Types.INTEGER);
|
if ("".equals(eamInstance.getComment())) {
|
||||||
|
bulkPs.setNull(7, Types.INTEGER);
|
||||||
|
} else {
|
||||||
|
bulkPs.setString(7, eamInstance.getComment());
|
||||||
|
}
|
||||||
|
bulkPs.addBatch();
|
||||||
} else {
|
} else {
|
||||||
bulkPs.setString(7, eamInstance.getComment());
|
logger.log(Level.WARNING, ("Artifact value too long for central repository."
|
||||||
|
+ "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
|
||||||
|
+ "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
|
||||||
|
+ "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue())
|
||||||
|
+ "\n\tEam Instance: "
|
||||||
|
+ "\n\t\tCaseId: " + eamInstance.getCorrelationDataSource().getCaseID()
|
||||||
|
+ "\n\t\tDeviceID: " + eamInstance.getCorrelationDataSource().getDeviceID()
|
||||||
|
+ "\n\t\tFilePath: " + eamInstance.getFilePath());
|
||||||
}
|
}
|
||||||
bulkPs.addBatch();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1740,11 +1774,13 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
|
|
||||||
return 0 < badInstances;
|
return 0 < badInstances;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the Artifact instance in the EamDb
|
* Process the Artifact instance in the EamDb
|
||||||
*
|
*
|
||||||
* @param type EamArtifact.Type to search for
|
* @param type EamArtifact.Type to search for
|
||||||
* @param instanceTableCallback callback to process the instance
|
* @param instanceTableCallback callback to process the instance
|
||||||
|
*
|
||||||
* @throws EamDbException
|
* @throws EamDbException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -67,6 +67,7 @@ public class CorrelationDataSource implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a CorrelationDataSource object from a TSK Content object.
|
* Create a CorrelationDataSource object from a TSK Content object.
|
||||||
|
* This will add it to the central repository.
|
||||||
*
|
*
|
||||||
* @param correlationCase the current CorrelationCase used for ensuring
|
* @param correlationCase the current CorrelationCase used for ensuring
|
||||||
* uniqueness of DataSource
|
* uniqueness of DataSource
|
||||||
|
@ -450,10 +450,10 @@ final class CaseEventListener implements PropertyChangeListener {
|
|||||||
correlationCase = dbManager.newCase(openCase);
|
correlationCase = dbManager.newCase(openCase);
|
||||||
}
|
}
|
||||||
if (null == dbManager.getDataSource(correlationCase, deviceId)) {
|
if (null == dbManager.getDataSource(correlationCase, deviceId)) {
|
||||||
dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource));
|
CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource);
|
||||||
}
|
}
|
||||||
} catch (EamDbException ex) {
|
} catch (EamDbException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error adding new data source to the central repository", ex); //NON-NLS
|
||||||
} catch (TskCoreException | TskDataException ex) {
|
} catch (TskCoreException | TskDataException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
|
@ -276,12 +276,12 @@ public class IngestEventsListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (FALSE == eamArtifacts.isEmpty()) {
|
if (FALSE == eamArtifacts.isEmpty()) {
|
||||||
try {
|
for (CorrelationAttribute eamArtifact : eamArtifacts) {
|
||||||
for (CorrelationAttribute eamArtifact : eamArtifacts) {
|
try {
|
||||||
dbManager.addArtifact(eamArtifact);
|
dbManager.addArtifact(eamArtifact);
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error adding artifact to database.", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
} catch (EamDbException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
|
|
||||||
}
|
}
|
||||||
} // DATA_ADDED
|
} // DATA_ADDED
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,6 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
|
|||||||
viewers.add(table);
|
viewers.add(table);
|
||||||
progress.setDisplayName(Bundle.CommonFilesPanel_search_done_searchProgressDisplay());
|
progress.setDisplayName(Bundle.CommonFilesPanel_search_done_searchProgressDisplay());
|
||||||
DataResultTopComponent.createInstance(tabTitle, pathText, tableFilterWithDescendantsNode, metadata.size(), viewers);
|
DataResultTopComponent.createInstance(tabTitle, pathText, tableFilterWithDescendantsNode, metadata.size(), viewers);
|
||||||
progress.finish();
|
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Interrupted while loading Common Files", ex);
|
LOGGER.log(Level.SEVERE, "Interrupted while loading Common Files", ex);
|
||||||
MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_search_done_interupted());
|
MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_search_done_interupted());
|
||||||
@ -285,6 +284,8 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
|
|||||||
errorMessage = Bundle.CommonFilesPanel_search_done_exception();
|
errorMessage = Bundle.CommonFilesPanel_search_done_exception();
|
||||||
}
|
}
|
||||||
MessageNotifyUtil.Message.error(errorMessage);
|
MessageNotifyUtil.Message.error(errorMessage);
|
||||||
|
} finally {
|
||||||
|
progress.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
|
@ -24,7 +24,6 @@ import org.openide.util.HelpCtx;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.actions.CallableSystemAction;
|
import org.openide.util.actions.CallableSystemAction;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.core.Installer;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
|
||||||
|
@ -23,23 +23,29 @@ import java.util.Collections;
|
|||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
import javax.swing.table.TableColumn;
|
import javax.swing.table.TableColumn;
|
||||||
import javax.swing.table.TableColumnModel;
|
import javax.swing.table.TableColumnModel;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>DataResultViewerTable</code> which overrides the default column
|
* <code>DataResultViewerTable</code> which overrides the default column header
|
||||||
* header width calculations. The <code>CommonFilesSearchResultsViewerTable</code>
|
* width calculations. The <code>CommonFilesSearchResultsViewerTable</code>
|
||||||
* presents multiple tiers of data which are not always present and it may not
|
* presents multiple tiers of data which are not always present and it may not
|
||||||
* make sense to try to calculate the column widths for such tables by sampling
|
* make sense to try to calculate the column widths for such tables by sampling
|
||||||
* rows and looking for wide cells. Rather, we just pick some reasonable values.
|
* rows and looking for wide cells. Rather, we just pick some reasonable values.
|
||||||
*/
|
*/
|
||||||
public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
||||||
|
|
||||||
private static final Map<String, Integer> COLUMN_WIDTHS;
|
private static final Map<String, Integer> COLUMN_WIDTHS;
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CommonFilesSearchResultsViewerTable.class.getName());
|
||||||
|
|
||||||
|
private static final int DEFAULT_WIDTH = 100;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Map<String, Integer> map = new HashMap<>();
|
Map<String, Integer> map = new HashMap<>();
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), 260);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), 260);
|
||||||
@ -63,18 +69,24 @@ public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
|||||||
"CommonFilesSearchResultsViewerTable.tagsColLbl1=Tags"
|
"CommonFilesSearchResultsViewerTable.tagsColLbl1=Tags"
|
||||||
})
|
})
|
||||||
@Override
|
@Override
|
||||||
protected void setColumnWidths(){
|
protected void setColumnWidths() {
|
||||||
TableColumnModel model = this.getColumnModel();
|
TableColumnModel model = this.getColumnModel();
|
||||||
|
|
||||||
Enumeration<TableColumn> columnsEnumerator = model.getColumns();
|
Enumeration<TableColumn> columnsEnumerator = model.getColumns();
|
||||||
while(columnsEnumerator.hasMoreElements()){
|
while (columnsEnumerator.hasMoreElements()) {
|
||||||
|
|
||||||
TableColumn column = columnsEnumerator.nextElement();
|
TableColumn column = columnsEnumerator.nextElement();
|
||||||
|
|
||||||
final String headerValue = column.getHeaderValue().toString();
|
final String headerValue = column.getHeaderValue().toString();
|
||||||
final Integer get = COLUMN_WIDTHS.get(headerValue);
|
|
||||||
|
|
||||||
column.setPreferredWidth(get);
|
final Integer defaultWidth = COLUMN_WIDTHS.get(headerValue);
|
||||||
|
|
||||||
|
if(defaultWidth == null){
|
||||||
|
column.setPreferredWidth(DEFAULT_WIDTH);
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Tried to set width on a column not supported by the CommonFilesSearchResultsViewerTable: %s", headerValue));
|
||||||
|
} else {
|
||||||
|
column.setPreferredWidth(defaultWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,6 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A file content viewer for SQLite database files.
|
* A file content viewer for SQLite database files.
|
||||||
@ -289,28 +288,22 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
fileChooser.setAcceptAllFileFilterUsed(true);
|
fileChooser.setAcceptAllFileFilterUsed(true);
|
||||||
fileChooser.setFileFilter(csvFilter);
|
fileChooser.setFileFilter(csvFilter);
|
||||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||||
|
String defaultFileName = (String) this.tablesDropdownList.getSelectedItem();
|
||||||
|
fileChooser.setSelectedFile(new File(defaultFileName));
|
||||||
int choice = fileChooser.showSaveDialog((Component) evt.getSource()); //TODO
|
int choice = fileChooser.showSaveDialog((Component) evt.getSource()); //TODO
|
||||||
if (JFileChooser.APPROVE_OPTION == choice) {
|
if (JFileChooser.APPROVE_OPTION == choice) {
|
||||||
boolean overwrite = false;
|
|
||||||
File file = fileChooser.getSelectedFile();
|
File file = fileChooser.getSelectedFile();
|
||||||
if (file == null) {
|
if (file.exists() && FilenameUtils.getExtension(file.getName()).equalsIgnoreCase("csv")) {
|
||||||
JOptionPane.showMessageDialog(this,
|
|
||||||
Bundle.SQLiteViewer_csvExport_fileName_empty(),
|
|
||||||
Bundle.SQLiteViewer_csvExport_title(),
|
|
||||||
JOptionPane.WARNING_MESSAGE);
|
|
||||||
return;
|
|
||||||
} else if (file.exists() && FilenameUtils.getExtension(file.getName()).equalsIgnoreCase("csv")) {
|
|
||||||
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(this,
|
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(this,
|
||||||
Bundle.SQLiteViewer_csvExport_confirm_msg(),
|
Bundle.SQLiteViewer_csvExport_confirm_msg(),
|
||||||
Bundle.SQLiteViewer_csvExport_title(),
|
Bundle.SQLiteViewer_csvExport_title(),
|
||||||
JOptionPane.YES_NO_OPTION)) {
|
JOptionPane.YES_NO_OPTION)) {
|
||||||
overwrite = true;
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exportTableToCsv(file, overwrite);
|
exportTableToCsv(file);
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_exportCsvButtonActionPerformed
|
}//GEN-LAST:event_exportCsvButtonActionPerformed
|
||||||
|
|
||||||
@ -567,9 +560,8 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
"SQLiteViewer.exportTableToCsv.FileName=File name: ",
|
"SQLiteViewer.exportTableToCsv.FileName=File name: ",
|
||||||
"SQLiteViewer.exportTableToCsv.TableName=Table name: "
|
"SQLiteViewer.exportTableToCsv.TableName=Table name: "
|
||||||
})
|
})
|
||||||
private void exportTableToCsv(File file, boolean overwrite) {
|
private void exportTableToCsv(File file) {
|
||||||
String tableName = (String) this.tablesDropdownList.getSelectedItem();
|
String tableName = (String) this.tablesDropdownList.getSelectedItem();
|
||||||
String csvFileSuffix = "_" + tableName + "_" + TimeStampUtils.createTimeStamp() + ".csv";
|
|
||||||
try (
|
try (
|
||||||
Statement statement = connection.createStatement();
|
Statement statement = connection.createStatement();
|
||||||
ResultSet resultSet = statement.executeQuery("SELECT * FROM " + tableName)) {
|
ResultSet resultSet = statement.executeQuery("SELECT * FROM " + tableName)) {
|
||||||
@ -578,42 +570,42 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
|||||||
if (Objects.isNull(currentTableRows) || currentTableRows.isEmpty()) {
|
if (Objects.isNull(currentTableRows) || currentTableRows.isEmpty()) {
|
||||||
logger.log(Level.INFO, String.format("The table %s is empty. (objId=%d)", tableName, sqliteDbFile.getId())); //NON-NLS
|
logger.log(Level.INFO, String.format("The table %s is empty. (objId=%d)", tableName, sqliteDbFile.getId())); //NON-NLS
|
||||||
} else {
|
} else {
|
||||||
String fileName = file.getName();
|
|
||||||
File csvFile;
|
File csvFile;
|
||||||
if (overwrite) {
|
String fileName = file.getName();
|
||||||
|
if (FilenameUtils.getExtension(fileName).equalsIgnoreCase("csv")) {
|
||||||
csvFile = file;
|
csvFile = file;
|
||||||
} else if (FilenameUtils.getExtension(fileName).equalsIgnoreCase("csv")) {
|
|
||||||
csvFile = new File(file.getParentFile(), FilenameUtils.removeExtension(fileName) + csvFileSuffix);
|
|
||||||
} else {
|
} else {
|
||||||
csvFile = new File(file.toString() + csvFileSuffix);
|
csvFile = new File(file.toString() + ".csv");
|
||||||
}
|
}
|
||||||
FileOutputStream out = new FileOutputStream(csvFile, false);
|
|
||||||
|
|
||||||
out.write((Bundle.SQLiteViewer_exportTableToCsv_FileName() + csvFile.getName() + "\n").getBytes());
|
try (FileOutputStream out = new FileOutputStream(csvFile, false)) {
|
||||||
out.write((Bundle.SQLiteViewer_exportTableToCsv_TableName() + tableName + "\n").getBytes());
|
|
||||||
// Set up the column names
|
|
||||||
Map<String, Object> row = currentTableRows.get(0);
|
|
||||||
StringBuffer header = new StringBuffer();
|
|
||||||
for (Map.Entry<String, Object> col : row.entrySet()) {
|
|
||||||
String colName = col.getKey();
|
|
||||||
if (header.length() > 0) {
|
|
||||||
header.append(',').append(colName);
|
|
||||||
} else {
|
|
||||||
header.append(colName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.write(header.append('\n').toString().getBytes());
|
|
||||||
|
|
||||||
for (Map<String, Object> maps : currentTableRows) {
|
out.write((Bundle.SQLiteViewer_exportTableToCsv_FileName() + csvFile.getName() + "\n").getBytes());
|
||||||
StringBuffer valueLine = new StringBuffer();
|
out.write((Bundle.SQLiteViewer_exportTableToCsv_TableName() + tableName + "\n").getBytes());
|
||||||
maps.values().forEach((value) -> {
|
// Set up the column names
|
||||||
if (valueLine.length() > 0) {
|
Map<String, Object> row = currentTableRows.get(0);
|
||||||
valueLine.append(',').append(value.toString());
|
StringBuffer header = new StringBuffer();
|
||||||
|
for (Map.Entry<String, Object> col : row.entrySet()) {
|
||||||
|
String colName = col.getKey();
|
||||||
|
if (header.length() > 0) {
|
||||||
|
header.append(',').append(colName);
|
||||||
} else {
|
} else {
|
||||||
valueLine.append(value.toString());
|
header.append(colName);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
out.write(valueLine.append('\n').toString().getBytes());
|
out.write(header.append('\n').toString().getBytes());
|
||||||
|
|
||||||
|
for (Map<String, Object> maps : currentTableRows) {
|
||||||
|
StringBuffer valueLine = new StringBuffer();
|
||||||
|
maps.values().forEach((value) -> {
|
||||||
|
if (valueLine.length() > 0) {
|
||||||
|
valueLine.append(',').append(value.toString());
|
||||||
|
} else {
|
||||||
|
valueLine.append(value.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
out.write(valueLine.append('\n').toString().getBytes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
|
@ -312,7 +312,11 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
"BlackboardArtifactNode.createSheet.artifactDetails.name=Artifact Details",
|
"BlackboardArtifactNode.createSheet.artifactDetails.name=Artifact Details",
|
||||||
"BlackboardArtifactNode.artifact.displayName=Artifact",
|
"BlackboardArtifactNode.artifact.displayName=Artifact",
|
||||||
"BlackboardArtifactNode.createSheet.artifactMD5.displayName=MD5 Hash",
|
"BlackboardArtifactNode.createSheet.artifactMD5.displayName=MD5 Hash",
|
||||||
"BlackboardArtifactNode.createSheet.artifactMD5.name=MD5 Hash"})
|
"BlackboardArtifactNode.createSheet.artifactMD5.name=MD5 Hash",
|
||||||
|
"BlackboardArtifactNode.createSheet.fileSize.name=Size",
|
||||||
|
"BlackboardArtifactNode.createSheet.fileSize.displayName=Size",
|
||||||
|
"BlackboardArtifactNode.createSheet.path.displayName=Path",
|
||||||
|
"BlackboardArtifactNode.createSheet.path.name=Path"})
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
@ -453,6 +457,31 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If EXIF, add props for file size and path
|
||||||
|
if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) {
|
||||||
|
|
||||||
|
long size = 0;
|
||||||
|
String path = ""; //NON-NLS
|
||||||
|
if (associated instanceof AbstractFile) {
|
||||||
|
AbstractFile af = (AbstractFile) associated;
|
||||||
|
size = af.getSize();
|
||||||
|
try {
|
||||||
|
path = af.getUniquePath();
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
path = af.getParentPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.name"),
|
||||||
|
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.displayName"),
|
||||||
|
NO_DESCR,
|
||||||
|
size));
|
||||||
|
sheetSet.put(new NodeProperty<>(
|
||||||
|
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.name"),
|
||||||
|
NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.displayName"),
|
||||||
|
NO_DESCR,
|
||||||
|
path));
|
||||||
|
}
|
||||||
|
|
||||||
addTagProperty(sheetSet);
|
addTagProperty(sheetSet);
|
||||||
|
|
||||||
return sheet;
|
return sheet;
|
||||||
|
@ -54,7 +54,6 @@ DataModelActionsFactory.srcFileInDir.text=View Source File in Directory
|
|||||||
DataModelActionsFactory.fileInDir.text=View File in Directory
|
DataModelActionsFactory.fileInDir.text=View File in Directory
|
||||||
DataModelActionsFactory.viewNewWin.text=View in New Window
|
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
|
|
||||||
DataSourcesNode.name=Data Sources
|
DataSourcesNode.name=Data Sources
|
||||||
DataSourcesNode.group_by_datasource.name=Data Source Files
|
DataSourcesNode.group_by_datasource.name=Data Source Files
|
||||||
DataSourcesNode.createSheet.name.name=Name
|
DataSourcesNode.createSheet.name.name=Name
|
||||||
|
@ -55,7 +55,6 @@ DataModelActionsFactory.srcFileInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u
|
|||||||
DataModelActionsFactory.fileInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u5185\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u8868\u793a
|
DataModelActionsFactory.fileInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u5185\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u8868\u793a
|
||||||
DataModelActionsFactory.viewNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30a6\u306b\u8868\u793a
|
DataModelActionsFactory.viewNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30a6\u306b\u8868\u793a
|
||||||
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
|
|
||||||
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.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
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* 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.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.openide.nodes.Children;
|
|
||||||
import org.openide.nodes.Sheet;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A dummy node used by the child factory to display while children are being
|
|
||||||
* generated
|
|
||||||
*/
|
|
||||||
public class CommonFileChildNodeLoading extends DisplayableItemNode {
|
|
||||||
|
|
||||||
public CommonFileChildNodeLoading(Children children) {
|
|
||||||
super(children);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
|
||||||
return visitor.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLeafTypeNode() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getItemType() {
|
|
||||||
return getClass().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Sheet createSheet() {
|
|
||||||
Sheet sheet = new Sheet();
|
|
||||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
|
||||||
if (sheetSet == null) {
|
|
||||||
sheetSet = Sheet.createPropertiesSet();
|
|
||||||
sheet.put(sheetSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> map = new LinkedHashMap<>();
|
|
||||||
map.put(CommonFileChildLoadingPropertyType.File.toString(), "Loading...");
|
|
||||||
|
|
||||||
final String NO_DESCR = Bundle.AbstractFsContentNode_noDesc_text();
|
|
||||||
for (CommonFileChildLoadingPropertyType propType : CommonFileChildLoadingPropertyType.values()) {
|
|
||||||
final String propString = propType.toString();
|
|
||||||
sheetSet.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the sole column for the 'dummy' loading node.
|
|
||||||
*/
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"CommonFileChildLoadingPropertyType.fileColLbl=File"
|
|
||||||
})
|
|
||||||
public enum CommonFileChildLoadingPropertyType {
|
|
||||||
|
|
||||||
File(Bundle.CommonFileChildLoadingPropertyType_fileColLbl());
|
|
||||||
|
|
||||||
final private String displayString;
|
|
||||||
|
|
||||||
private CommonFileChildLoadingPropertyType(String displayString) {
|
|
||||||
this.displayString = displayString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return displayString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -38,7 +38,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
|||||||
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
|
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
@ -76,8 +75,6 @@ public class DataModelActionsFactory {
|
|||||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.viewNewWin.text");
|
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.viewNewWin.text");
|
||||||
public static final String OPEN_IN_EXTERNAL_VIEWER = NbBundle
|
public static final String OPEN_IN_EXTERNAL_VIEWER = NbBundle
|
||||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.openExtViewer.text");
|
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.openExtViewer.text");
|
||||||
public static final String SEARCH_FOR_FILES_SAME_MD5 = NbBundle
|
|
||||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.srfFileSameMD5.text");
|
|
||||||
|
|
||||||
public static List<Action> getActions(File file, boolean isArtifactSource) {
|
public static List<Action> getActions(File file, boolean isArtifactSource) {
|
||||||
List<Action> actionsList = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
@ -88,7 +85,6 @@ public class DataModelActionsFactory {
|
|||||||
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, fileNode));
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -367,7 +363,6 @@ public class DataModelActionsFactory {
|
|||||||
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, tagNode));
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -404,7 +399,6 @@ public class DataModelActionsFactory {
|
|||||||
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, tagNode));
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
|
@ -121,8 +121,6 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
|
|
||||||
T visit(FileInstanceNode fin);
|
T visit(FileInstanceNode fin);
|
||||||
|
|
||||||
T visit(CommonFileChildNodeLoading cfcnl);
|
|
||||||
|
|
||||||
T visit(InstanceCountNode icn);
|
T visit(InstanceCountNode icn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -213,11 +211,6 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
return defaultVisit(icn);
|
return defaultVisit(icn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public T visit(CommonFileChildNodeLoading cfcnl) {
|
|
||||||
return defaultVisit(cfcnl);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(DirectoryNode dn) {
|
public T visit(DirectoryNode dn) {
|
||||||
return defaultVisit(dn);
|
return defaultVisit(dn);
|
||||||
|
@ -34,7 +34,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
||||||
@ -166,7 +165,6 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
actionsList.add(null); // Creates an item separator
|
actionsList.add(null); // Creates an item separator
|
||||||
|
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(Bundle.FileNode_getActions_searchFilesSameMD5_text(), this));
|
|
||||||
actionsList.add(null); // Creates an item separator
|
actionsList.add(null); // Creates an item separator
|
||||||
|
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
||||||
@ -107,8 +106,6 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
|||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
|
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(
|
|
||||||
NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.searchFilesSameMd5.text"), this));
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
@ -120,3 +120,8 @@ 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
|
DirectoryTreeTopComponent.groupByDatasourceCheckBox.text=Group by Data Source
|
||||||
|
GroupDataSourcesDialog.dataSourceCountLabel.text=jLabel1
|
||||||
|
GroupDataSourcesDialog.queryLabel.text=Would you like to group by data source for faster loading?
|
||||||
|
GroupDataSourcesDialog.yesButton.text=Yes
|
||||||
|
GroupDataSourcesDialog.noButton.text=No
|
||||||
|
GroupDataSourcesDialog.title=Group by Data Source?
|
@ -401,10 +401,8 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
}
|
}
|
||||||
Content c = ban.getLookup().lookup(File.class);
|
Content c = ban.getLookup().lookup(File.class);
|
||||||
Node n = null;
|
Node n = null;
|
||||||
boolean md5Action = false;
|
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
n = new FileNode((AbstractFile) c);
|
n = new FileNode((AbstractFile) c);
|
||||||
md5Action = true;
|
|
||||||
} else if ((c = ban.getLookup().lookup(Directory.class)) != null) {
|
} else if ((c = ban.getLookup().lookup(Directory.class)) != null) {
|
||||||
n = new DirectoryNode((Directory) c);
|
n = new DirectoryNode((Directory) c);
|
||||||
} else if ((c = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
|
} else if ((c = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
|
||||||
@ -438,10 +436,6 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
|
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
if (md5Action) {
|
|
||||||
actionsList.add(new HashSearchAction(
|
|
||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.searchFilesSameMd5.text"), n));
|
|
||||||
}
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
|
@ -24,6 +24,11 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyVetoException;
|
import java.beans.PropertyVetoException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
@ -35,6 +40,7 @@ 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;
|
||||||
import java.util.prefs.PreferenceChangeListener;
|
import java.util.prefs.PreferenceChangeListener;
|
||||||
|
import java.util.Properties;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
@ -62,6 +68,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataExplorer;
|
|||||||
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
||||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
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;
|
||||||
@ -103,6 +110,9 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(DirectoryTreeTopComponent.class.getName());
|
||||||
private AutopsyTreeChildrenFactory autopsyTreeChildrenFactory;
|
private AutopsyTreeChildrenFactory autopsyTreeChildrenFactory;
|
||||||
private Children autopsyTreeChildren;
|
private Children autopsyTreeChildren;
|
||||||
|
private static final long DEFAULT_DATASOURCE_GROUPING_THRESHOLD = 5; // Threshold for prompting the user about grouping by data source
|
||||||
|
private static final String GROUPING_THRESHOLD_NAME = "GroupDataSourceThreshold";
|
||||||
|
private static final String SETTINGS_FILE = "CasePreferences.properties"; //NON-NLS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the constructor
|
* the constructor
|
||||||
@ -370,6 +380,50 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
return TopComponent.PERSISTENCE_NEVER;
|
return TopComponent.PERSISTENCE_NEVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask the user if they want to group by data source when opening a large case.
|
||||||
|
*
|
||||||
|
* @param currentCase
|
||||||
|
* @param dataSourceCount
|
||||||
|
*/
|
||||||
|
private void promptForDataSourceGrouping(Case currentCase, int dataSourceCount) {
|
||||||
|
Path settingsFile = Paths.get(currentCase.getConfigDirectory(), SETTINGS_FILE); //NON-NLS
|
||||||
|
if (settingsFile.toFile().exists()) {
|
||||||
|
// Read the setting
|
||||||
|
try (InputStream inputStream = Files.newInputStream(settingsFile)) {
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.load(inputStream);
|
||||||
|
if (props.getProperty("groupByDataSource", "false").equals("true")) {
|
||||||
|
UserPreferences.setGroupItemsInTreeByDatasource(true);
|
||||||
|
groupByDatasourceCheckBox.setSelected(true);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error reading settings file", ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GroupDataSourcesDialog dialog = new GroupDataSourcesDialog(dataSourceCount);
|
||||||
|
dialog.display();
|
||||||
|
if (dialog.groupByDataSourceSelected()) {
|
||||||
|
UserPreferences.setGroupItemsInTreeByDatasource(true);
|
||||||
|
groupByDatasourceCheckBox.setSelected(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the response
|
||||||
|
Properties props = new Properties();
|
||||||
|
if(dialog.groupByDataSourceSelected()) {
|
||||||
|
props.setProperty("groupByDataSource", "true");
|
||||||
|
} else {
|
||||||
|
props.setProperty("groupByDataSource", "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (OutputStream fos = Files.newOutputStream(settingsFile)) {
|
||||||
|
props.store(fos, ""); //NON-NLS
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error writing settings file", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called only when top component was closed on all workspaces before and
|
* Called only when top component was closed on all workspaces before and
|
||||||
* now is opened for the first time on some workspace. The intent is to
|
* now is opened for the first time on some workspace. The intent is to
|
||||||
@ -377,6 +431,9 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
* existing workspaces. Subclasses will usually perform initializing tasks
|
* existing workspaces. Subclasses will usually perform initializing tasks
|
||||||
* here.
|
* here.
|
||||||
*/
|
*/
|
||||||
|
@NbBundle.Messages({"# {0} - dataSourceCount",
|
||||||
|
"DirectoryTreeTopComponent.componentOpened.groupDataSources.text=This case contains {0} data sources. Would you like to group by data source for faster loading?",
|
||||||
|
"DirectoryTreeTopComponent.componentOpened.groupDataSources.title=Group by data source?"})
|
||||||
@Override
|
@Override
|
||||||
public void componentOpened() {
|
public void componentOpened() {
|
||||||
// change the cursor to "waiting cursor" for this operation
|
// change the cursor to "waiting cursor" for this operation
|
||||||
@ -392,6 +449,31 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
if (null == currentCase || currentCase.hasData() == false) {
|
if (null == currentCase || currentCase.hasData() == false) {
|
||||||
getTree().setRootVisible(false); // hide the root
|
getTree().setRootVisible(false); // hide the root
|
||||||
} else {
|
} else {
|
||||||
|
// If the case contains a lot of data sources, and they aren't already grouping
|
||||||
|
// by data source, give the user the option to do so before loading the tree.
|
||||||
|
if (RuntimeProperties.runningWithGUI()) {
|
||||||
|
long threshold = DEFAULT_DATASOURCE_GROUPING_THRESHOLD;
|
||||||
|
if (ModuleSettings.settingExists(ModuleSettings.MAIN_SETTINGS, GROUPING_THRESHOLD_NAME)) {
|
||||||
|
try {
|
||||||
|
threshold = Long.parseLong(ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, GROUPING_THRESHOLD_NAME));
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Group data sources threshold is not a number", ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, GROUPING_THRESHOLD_NAME, String.valueOf(threshold));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int dataSourceCount = currentCase.getDataSources().size();
|
||||||
|
if (! UserPreferences.groupItemsInTreeByDatasource() &&
|
||||||
|
dataSourceCount > threshold) {
|
||||||
|
promptForDataSourceGrouping(currentCase, dataSourceCount);
|
||||||
|
}
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error loading data sources", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if there's at least one image, load the image and open the top componen
|
// if there's at least one image, load the image and open the top componen
|
||||||
autopsyTreeChildrenFactory = new AutopsyTreeChildrenFactory();
|
autopsyTreeChildrenFactory = new AutopsyTreeChildrenFactory();
|
||||||
autopsyTreeChildren = Children.create(autopsyTreeChildrenFactory, true);
|
autopsyTreeChildren = Children.create(autopsyTreeChildrenFactory, true);
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
|
||||||
|
<Properties>
|
||||||
|
<Property name="defaultCloseOperation" type="int" value="2"/>
|
||||||
|
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="GroupDataSourcesDialog.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<SyntheticProperties>
|
||||||
|
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||||
|
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
||||||
|
</SyntheticProperties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="queryLabel" max="32767" attributes="0"/>
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Component id="dataSourceCountLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Group type="102" alignment="1" attributes="0">
|
||||||
|
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||||
|
<Component id="yesButton" min="-2" pref="76" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="noButton" min="-2" pref="76" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="dataSourceCountLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="queryLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="yesButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="noButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JLabel" name="dataSourceCountLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="GroupDataSourcesDialog.dataSourceCountLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="queryLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="GroupDataSourcesDialog.queryLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="yesButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="GroupDataSourcesDialog.yesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="yesButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="noButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="GroupDataSourcesDialog.noButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="noButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-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.directorytree;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.windows.WindowManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
|
final class GroupDataSourcesDialog extends javax.swing.JDialog {
|
||||||
|
|
||||||
|
boolean shouldGroupByDataSource = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new form GroupDataSourcesDialog
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({"# {0} - dataSourceCount",
|
||||||
|
"GroupDataSourcesDialog.groupDataSources.text=This case contains {0} data sources."})
|
||||||
|
GroupDataSourcesDialog(int dataSourceCount) {
|
||||||
|
super((JFrame) WindowManager.getDefault().getMainWindow());
|
||||||
|
initComponents();
|
||||||
|
dataSourceCountLabel.setText(Bundle.GroupDataSourcesDialog_groupDataSources_text(dataSourceCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the dialog.
|
||||||
|
*/
|
||||||
|
void display() {
|
||||||
|
setModal(true);
|
||||||
|
setSize(getPreferredSize());
|
||||||
|
setLocationRelativeTo(this.getParent());
|
||||||
|
setAlwaysOnTop(false);
|
||||||
|
pack();
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean groupByDataSourceSelected() {
|
||||||
|
return shouldGroupByDataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called from within the constructor to initialize the form.
|
||||||
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
* regenerated by the Form Editor.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
dataSourceCountLabel = new javax.swing.JLabel();
|
||||||
|
queryLabel = new javax.swing.JLabel();
|
||||||
|
yesButton = new javax.swing.JButton();
|
||||||
|
noButton = new javax.swing.JButton();
|
||||||
|
|
||||||
|
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
|
setTitle(org.openide.util.NbBundle.getMessage(GroupDataSourcesDialog.class, "GroupDataSourcesDialog.title")); // NOI18N
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(dataSourceCountLabel, org.openide.util.NbBundle.getMessage(GroupDataSourcesDialog.class, "GroupDataSourcesDialog.dataSourceCountLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(queryLabel, org.openide.util.NbBundle.getMessage(GroupDataSourcesDialog.class, "GroupDataSourcesDialog.queryLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(yesButton, org.openide.util.NbBundle.getMessage(GroupDataSourcesDialog.class, "GroupDataSourcesDialog.yesButton.text")); // NOI18N
|
||||||
|
yesButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
yesButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(noButton, org.openide.util.NbBundle.getMessage(GroupDataSourcesDialog.class, "GroupDataSourcesDialog.noButton.text")); // NOI18N
|
||||||
|
noButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
noButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||||
|
getContentPane().setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(queryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addComponent(dataSourceCountLabel)
|
||||||
|
.addGap(0, 0, Short.MAX_VALUE))
|
||||||
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||||
|
.addGap(0, 0, Short.MAX_VALUE)
|
||||||
|
.addComponent(yesButton, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(noButton, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addComponent(dataSourceCountLabel)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(queryLabel)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(yesButton)
|
||||||
|
.addComponent(noButton))
|
||||||
|
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
|
||||||
|
pack();
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void yesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_yesButtonActionPerformed
|
||||||
|
shouldGroupByDataSource = true;
|
||||||
|
dispose();
|
||||||
|
}//GEN-LAST:event_yesButtonActionPerformed
|
||||||
|
|
||||||
|
private void noButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_noButtonActionPerformed
|
||||||
|
shouldGroupByDataSource = false;
|
||||||
|
dispose();
|
||||||
|
}//GEN-LAST:event_noButtonActionPerformed
|
||||||
|
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JLabel dataSourceCountLabel;
|
||||||
|
private javax.swing.JButton noButton;
|
||||||
|
private javax.swing.JLabel queryLabel;
|
||||||
|
private javax.swing.JButton yesButton;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
}
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2011 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.directorytree;
|
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import org.openide.nodes.Node;
|
|
||||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbSearchAction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to lookup the interface and call the real action in HashDatabase. The
|
|
||||||
* real action, HashDbSearchAction, implements HashSearchProvider, and should be
|
|
||||||
* the only instance of it.
|
|
||||||
*
|
|
||||||
* //TODO: HashDBSearchAction needs a public constructor and a service
|
|
||||||
* registration annotation for the lookup technique to work
|
|
||||||
*/
|
|
||||||
@Immutable
|
|
||||||
public class HashSearchAction extends AbstractAction {
|
|
||||||
|
|
||||||
private final Node contentNode;
|
|
||||||
|
|
||||||
public HashSearchAction(String title, Node contentNode) {
|
|
||||||
super(title);
|
|
||||||
this.contentNode = contentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
//HashSearchProvider searcher = Lookup.getDefault().lookup(HashSearchProvider.class);
|
|
||||||
//TODO: HashDBSearchAction needs a public constructor and a service registration annotation for the above technique to work
|
|
||||||
HashDbSearchAction searcher = HashDbSearchAction.getDefault();
|
|
||||||
searcher.search(contentNode);
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.filesearch;
|
package org.sleuthkit.autopsy.filesearch;
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.awt.event.MouseMotionListener;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -29,7 +27,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
@ -47,7 +44,6 @@ public class DataSourcePanel extends javax.swing.JPanel {
|
|||||||
private static final Logger logger = Logger.getLogger(DataSourcePanel.class.getName());
|
private static final Logger logger = Logger.getLogger(DataSourcePanel.class.getName());
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private final Map<Long, String> dataSourceMap = new HashMap<>();
|
private final Map<Long, String> dataSourceMap = new HashMap<>();
|
||||||
private final List<String> toolTipList = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new form DataSourcePanel
|
* Creates new form DataSourcePanel
|
||||||
@ -57,28 +53,10 @@ public class DataSourcePanel extends javax.swing.JPanel {
|
|||||||
this.dataSourceList.addListSelectionListener((ListSelectionEvent evt) -> {
|
this.dataSourceList.addListSelectionListener((ListSelectionEvent evt) -> {
|
||||||
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
});
|
});
|
||||||
this.dataSourceList.addMouseMotionListener(new MouseMotionListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseDragged(MouseEvent evt) {
|
|
||||||
//Unused by now
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseMoved(MouseEvent evt) {
|
|
||||||
if (evt.getSource() instanceof JList<?>) {
|
|
||||||
JList<?> dsList = (JList<?>) evt.getSource();
|
|
||||||
int index = dsList.locationToIndex(evt.getPoint());
|
|
||||||
if (index > -1) {
|
|
||||||
dsList.setToolTipText(toolTipList.get(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get dataSourceMap with object id and data source display name. Add the data source full name to toolTipList
|
* Get dataSourceMap with object id and data source display name.
|
||||||
*
|
*
|
||||||
* @return The list of data source name
|
* @return The list of data source name
|
||||||
*/
|
*/
|
||||||
@ -94,7 +72,6 @@ public class DataSourcePanel extends javax.swing.JPanel {
|
|||||||
File dataSourceFullName = new File(dsName);
|
File dataSourceFullName = new File(dsName);
|
||||||
String displayName = dataSourceFullName.getName();
|
String displayName = dataSourceFullName.getName();
|
||||||
dataSourceMap.put(ds.getId(), displayName);
|
dataSourceMap.put(ds.getId(), displayName);
|
||||||
toolTipList.add(dsName);
|
|
||||||
dsList.add(displayName);
|
dsList.add(displayName);
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException ex) {
|
} catch (NoCurrentCaseException ex) {
|
||||||
|
@ -556,17 +556,29 @@ class ReportHTML implements TableReportModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a row to the current table.
|
* Add a row to the current table, escaping the text to be contained in the
|
||||||
|
* row.
|
||||||
*
|
*
|
||||||
* @param row values for each cell in the row
|
* @param row values for each cell in the row
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addRow(List<String> row) {
|
public void addRow(List<String> row) {
|
||||||
|
addRow(row, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a row to the current table.
|
||||||
|
*
|
||||||
|
* @param row values for each cell in the row
|
||||||
|
* @param escapeText whether or not the text of the row should be escaped,
|
||||||
|
* true for escaped, false for not escaped
|
||||||
|
*/
|
||||||
|
private void addRow(List<String> row, boolean escapeText) {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
builder.append("\t<tr>\n"); //NON-NLS
|
builder.append("\t<tr>\n"); //NON-NLS
|
||||||
for (String cell : row) {
|
for (String cell : row) {
|
||||||
String escapeHTMLCell = EscapeUtil.escapeHtml(cell);
|
String cellText = escapeText ? EscapeUtil.escapeHtml(cell) : cell;
|
||||||
builder.append("\t\t<td>").append(escapeHTMLCell).append("</td>\n"); //NON-NLS
|
builder.append("\t\t<td>").append(cellText).append("</td>\n"); //NON-NLS
|
||||||
}
|
}
|
||||||
builder.append("\t</tr>\n"); //NON-NLS
|
builder.append("\t</tr>\n"); //NON-NLS
|
||||||
rowCount++;
|
rowCount++;
|
||||||
@ -593,7 +605,7 @@ class ReportHTML implements TableReportModule {
|
|||||||
public void addRowWithTaggedContentHyperlink(List<String> row, ContentTag contentTag) {
|
public void addRowWithTaggedContentHyperlink(List<String> row, ContentTag contentTag) {
|
||||||
Content content = contentTag.getContent();
|
Content content = contentTag.getContent();
|
||||||
if (content instanceof AbstractFile == false) {
|
if (content instanceof AbstractFile == false) {
|
||||||
addRow(row);
|
addRow(row, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AbstractFile file = (AbstractFile) content;
|
AbstractFile file = (AbstractFile) content;
|
||||||
@ -647,7 +659,7 @@ class ReportHTML implements TableReportModule {
|
|||||||
int pages = 1;
|
int pages = 1;
|
||||||
for (Content content : images) {
|
for (Content content : images) {
|
||||||
if (currentRow.size() == THUMBNAIL_COLUMNS) {
|
if (currentRow.size() == THUMBNAIL_COLUMNS) {
|
||||||
addRow(currentRow);
|
addRow(currentRow, false);
|
||||||
currentRow.clear();
|
currentRow.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,7 +739,7 @@ class ReportHTML implements TableReportModule {
|
|||||||
// Finish out the row.
|
// Finish out the row.
|
||||||
currentRow.add("");
|
currentRow.add("");
|
||||||
}
|
}
|
||||||
addRow(currentRow);
|
addRow(currentRow, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// manually set rowCount to be the total number of images.
|
// manually set rowCount to be the total number of images.
|
||||||
@ -1094,8 +1106,8 @@ class ReportHTML implements TableReportModule {
|
|||||||
summary.append("<div class=\"title\">\n"); //NON-NLS
|
summary.append("<div class=\"title\">\n"); //NON-NLS
|
||||||
summary.append(writeSummaryCaseDetails());
|
summary.append(writeSummaryCaseDetails());
|
||||||
summary.append(writeSummaryImageInfo());
|
summary.append(writeSummaryImageInfo());
|
||||||
summary.append(writeSummarySoftwareInfo(skCase,ingestJobs));
|
summary.append(writeSummarySoftwareInfo(skCase, ingestJobs));
|
||||||
summary.append(writeSummaryIngestHistoryInfo(skCase,ingestJobs));
|
summary.append(writeSummaryIngestHistoryInfo(skCase, ingestJobs));
|
||||||
if (generatorLogoSet) {
|
if (generatorLogoSet) {
|
||||||
summary.append("<div class=\"left\">\n"); //NON-NLS
|
summary.append("<div class=\"left\">\n"); //NON-NLS
|
||||||
summary.append("<img src=\"generator_logo.png\" />\n"); //NON-NLS
|
summary.append("<img src=\"generator_logo.png\" />\n"); //NON-NLS
|
||||||
@ -1132,8 +1144,7 @@ class ReportHTML implements TableReportModule {
|
|||||||
*
|
*
|
||||||
* @return StringBuilder updated html report with case details
|
* @return StringBuilder updated html report with case details
|
||||||
*/
|
*/
|
||||||
|
private StringBuilder writeSummaryCaseDetails() {
|
||||||
private StringBuilder writeSummaryCaseDetails(){
|
|
||||||
StringBuilder summary = new StringBuilder();
|
StringBuilder summary = new StringBuilder();
|
||||||
String caseName = currentCase.getDisplayName();
|
String caseName = currentCase.getDisplayName();
|
||||||
String caseNumber = currentCase.getNumber();
|
String caseNumber = currentCase.getNumber();
|
||||||
@ -1146,32 +1157,32 @@ class ReportHTML implements TableReportModule {
|
|||||||
imagecount = 0;
|
imagecount = 0;
|
||||||
}
|
}
|
||||||
summary.append("<div class=\"title\">\n"); //NON-NLS
|
summary.append("<div class=\"title\">\n"); //NON-NLS
|
||||||
if (agencyLogoSet) {
|
if (agencyLogoSet) {
|
||||||
summary.append("<div class=\"left\">\n"); //NON-NLS
|
summary.append("<div class=\"left\">\n"); //NON-NLS
|
||||||
summary.append("<img src=\"");
|
summary.append("<img src=\"");
|
||||||
summary.append(Paths.get(reportBranding.getAgencyLogoPath()).getFileName().toString());
|
summary.append(Paths.get(reportBranding.getAgencyLogoPath()).getFileName().toString());
|
||||||
summary.append("\" />\n"); //NON-NLS
|
summary.append("\" />\n"); //NON-NLS
|
||||||
summary.append("</div>\n"); //NON-NLS
|
|
||||||
}
|
|
||||||
final String align = agencyLogoSet ? "right" : "left"; //NON-NLS NON-NLS
|
|
||||||
summary.append("<div class=\"").append(align).append("\">\n"); //NON-NLS
|
|
||||||
summary.append("<table>\n"); //NON-NLS
|
|
||||||
summary.append("<tr><td>").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.caseName")) //NON-NLS
|
|
||||||
.append("</td><td>").append(caseName).append("</td></tr>\n"); //NON-NLS NON-NLS
|
|
||||||
summary.append("<tr><td>").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.caseNum")) //NON-NLS
|
|
||||||
.append("</td><td>").append(!caseNumber.isEmpty() ? caseNumber : NbBundle //NON-NLS
|
|
||||||
.getMessage(this.getClass(), "ReportHTML.writeSum.noCaseNum")).append("</td></tr>\n"); //NON-NLS
|
|
||||||
summary.append("<tr><td>").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.examiner")).append("</td><td>") //NON-NLS
|
|
||||||
.append(!examiner.isEmpty() ? examiner : NbBundle
|
|
||||||
.getMessage(this.getClass(), "ReportHTML.writeSum.noExaminer"))
|
|
||||||
.append("</td></tr>\n"); //NON-NLS
|
|
||||||
summary.append("<tr><td>").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.numImages")) //NON-NLS
|
|
||||||
.append("</td><td>").append(imagecount).append("</td></tr>\n"); //NON-NLS
|
|
||||||
summary.append("</table>\n"); //NON-NLS
|
|
||||||
summary.append("</div>\n"); //NON-NLS
|
summary.append("</div>\n"); //NON-NLS
|
||||||
summary.append("<div class=\"clear\"></div>\n"); //NON-NLS
|
}
|
||||||
summary.append("</div>\n"); //NON-NLS
|
final String align = agencyLogoSet ? "right" : "left"; //NON-NLS NON-NLS
|
||||||
return summary;
|
summary.append("<div class=\"").append(align).append("\">\n"); //NON-NLS
|
||||||
|
summary.append("<table>\n"); //NON-NLS
|
||||||
|
summary.append("<tr><td>").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.caseName")) //NON-NLS
|
||||||
|
.append("</td><td>").append(caseName).append("</td></tr>\n"); //NON-NLS NON-NLS
|
||||||
|
summary.append("<tr><td>").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.caseNum")) //NON-NLS
|
||||||
|
.append("</td><td>").append(!caseNumber.isEmpty() ? caseNumber : NbBundle //NON-NLS
|
||||||
|
.getMessage(this.getClass(), "ReportHTML.writeSum.noCaseNum")).append("</td></tr>\n"); //NON-NLS
|
||||||
|
summary.append("<tr><td>").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.examiner")).append("</td><td>") //NON-NLS
|
||||||
|
.append(!examiner.isEmpty() ? examiner : NbBundle
|
||||||
|
.getMessage(this.getClass(), "ReportHTML.writeSum.noExaminer"))
|
||||||
|
.append("</td></tr>\n"); //NON-NLS
|
||||||
|
summary.append("<tr><td>").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.numImages")) //NON-NLS
|
||||||
|
.append("</td><td>").append(imagecount).append("</td></tr>\n"); //NON-NLS
|
||||||
|
summary.append("</table>\n"); //NON-NLS
|
||||||
|
summary.append("</div>\n"); //NON-NLS
|
||||||
|
summary.append("<div class=\"clear\"></div>\n"); //NON-NLS
|
||||||
|
summary.append("</div>\n"); //NON-NLS
|
||||||
|
return summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1179,7 +1190,6 @@ class ReportHTML implements TableReportModule {
|
|||||||
*
|
*
|
||||||
* @return StringBuilder updated html report with Image Information
|
* @return StringBuilder updated html report with Image Information
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private StringBuilder writeSummaryImageInfo() {
|
private StringBuilder writeSummaryImageInfo() {
|
||||||
StringBuilder summary = new StringBuilder();
|
StringBuilder summary = new StringBuilder();
|
||||||
summary.append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.imageInfoHeading"));
|
summary.append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.imageInfoHeading"));
|
||||||
@ -1214,7 +1224,6 @@ class ReportHTML implements TableReportModule {
|
|||||||
*
|
*
|
||||||
* @return StringBuilder updated html report with software information
|
* @return StringBuilder updated html report with software information
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private StringBuilder writeSummarySoftwareInfo(SleuthkitCase skCase, List<IngestJobInfo> ingestJobs) {
|
private StringBuilder writeSummarySoftwareInfo(SleuthkitCase skCase, List<IngestJobInfo> ingestJobs) {
|
||||||
StringBuilder summary = new StringBuilder();
|
StringBuilder summary = new StringBuilder();
|
||||||
summary.append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.softwareInfoHeading"));
|
summary.append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.softwareInfoHeading"));
|
||||||
@ -1250,7 +1259,6 @@ class ReportHTML implements TableReportModule {
|
|||||||
*
|
*
|
||||||
* @return StringBuilder updated html report with ingest history
|
* @return StringBuilder updated html report with ingest history
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private StringBuilder writeSummaryIngestHistoryInfo(SleuthkitCase skCase, List<IngestJobInfo> ingestJobs) {
|
private StringBuilder writeSummaryIngestHistoryInfo(SleuthkitCase skCase, List<IngestJobInfo> ingestJobs) {
|
||||||
StringBuilder summary = new StringBuilder();
|
StringBuilder summary = new StringBuilder();
|
||||||
try {
|
try {
|
||||||
|
@ -33,7 +33,6 @@ import org.apache.commons.io.FileUtils;
|
|||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.LocalDiskDSProcessor;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.LocalFilesDSProcessor;
|
import org.sleuthkit.autopsy.casemodule.LocalFilesDSProcessor;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
import static org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
|
import static org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
|
||||||
|
@ -2790,6 +2790,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
sysLogger.log(Level.INFO, "Finished ingest modules analysis for {0} ", manifestPath);
|
sysLogger.log(Level.INFO, "Finished ingest modules analysis for {0} ", manifestPath);
|
||||||
IngestJob.ProgressSnapshot jobSnapshot = ingestJob.getSnapshot();
|
IngestJob.ProgressSnapshot jobSnapshot = ingestJob.getSnapshot();
|
||||||
for (IngestJob.ProgressSnapshot.DataSourceProcessingSnapshot snapshot : jobSnapshot.getDataSourceSnapshots()) {
|
for (IngestJob.ProgressSnapshot.DataSourceProcessingSnapshot snapshot : jobSnapshot.getDataSourceSnapshots()) {
|
||||||
|
AutoIngestJobLogger nestedJobLogger = new AutoIngestJobLogger(manifestPath, snapshot.getDataSource(), caseDirectoryPath);
|
||||||
if (!snapshot.isCancelled()) {
|
if (!snapshot.isCancelled()) {
|
||||||
List<String> cancelledModules = snapshot.getCancelledDataSourceIngestModules();
|
List<String> cancelledModules = snapshot.getCancelledDataSourceIngestModules();
|
||||||
if (!cancelledModules.isEmpty()) {
|
if (!cancelledModules.isEmpty()) {
|
||||||
@ -2798,15 +2799,15 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
||||||
for (String module : snapshot.getCancelledDataSourceIngestModules()) {
|
for (String module : snapshot.getCancelledDataSourceIngestModules()) {
|
||||||
sysLogger.log(Level.WARNING, String.format("%s ingest module cancelled for %s", module, manifestPath));
|
sysLogger.log(Level.WARNING, String.format("%s ingest module cancelled for %s", module, manifestPath));
|
||||||
jobLogger.logIngestModuleCancelled(module);
|
nestedJobLogger.logIngestModuleCancelled(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jobLogger.logAnalysisCompleted();
|
nestedJobLogger.logAnalysisCompleted();
|
||||||
} else {
|
} else {
|
||||||
currentJob.setProcessingStage(AutoIngestJob.Stage.CANCELLING, Date.from(Instant.now()));
|
currentJob.setProcessingStage(AutoIngestJob.Stage.CANCELLING, Date.from(Instant.now()));
|
||||||
currentJob.setErrorsOccurred(true);
|
currentJob.setErrorsOccurred(true);
|
||||||
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
||||||
jobLogger.logAnalysisCancelled();
|
nestedJobLogger.logAnalysisCancelled();
|
||||||
CancellationReason cancellationReason = snapshot.getCancellationReason();
|
CancellationReason cancellationReason = snapshot.getCancellationReason();
|
||||||
if (CancellationReason.NOT_CANCELLED != cancellationReason && CancellationReason.USER_CANCELLED != cancellationReason) {
|
if (CancellationReason.NOT_CANCELLED != cancellationReason && CancellationReason.USER_CANCELLED != cancellationReason) {
|
||||||
throw new AnalysisStartupException(String.format("Analysis cancelled due to %s for %s", cancellationReason.getDisplayName(), manifestPath));
|
throw new AnalysisStartupException(String.format("Analysis cancelled due to %s for %s", cancellationReason.getDisplayName(), manifestPath));
|
||||||
|
@ -106,10 +106,22 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter
|
|||||||
try {
|
try {
|
||||||
imageInMemory = IOUtils.toByteArray(inputStream);
|
imageInMemory = IOUtils.toByteArray(inputStream);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.log(Level.WARNING, "Unable to perform object detection on " + file.getName(), ex);
|
logger.log(Level.WARNING, "Unable to read image to byte array for performing object detection on " + file.getParentPath() + file.getName() + " with object id of " + file.getId(), ex);
|
||||||
return IngestModule.ProcessResult.ERROR;
|
return IngestModule.ProcessResult.ERROR;
|
||||||
}
|
}
|
||||||
Mat originalImage = Highgui.imdecode(new MatOfByte(imageInMemory), Highgui.IMREAD_GRAYSCALE);
|
Mat originalImage;
|
||||||
|
try {
|
||||||
|
originalImage = Highgui.imdecode(new MatOfByte(imageInMemory), Highgui.IMREAD_GRAYSCALE);
|
||||||
|
} catch (CvException ex) {
|
||||||
|
//The image was something which could not be decoded by OpenCv, our isImageThumbnailSupported(file) check above failed us
|
||||||
|
logger.log(Level.WARNING, "Unable to decode image from byte array to perform object detection on " + file.getParentPath() + file.getName() + " with object id of " + file.getId(), ex); //NON-NLS
|
||||||
|
return IngestModule.ProcessResult.ERROR;
|
||||||
|
} catch (Exception unexpectedException) {
|
||||||
|
//hopefully an unnecessary generic exception catch but currently present to catch any exceptions OpenCv throws which may not be documented
|
||||||
|
logger.log(Level.SEVERE, "Unexpected Exception encountered attempting to use OpenCV to decode picture: " + file.getParentPath() + file.getName() + " with object id of " + file.getId(), unexpectedException);
|
||||||
|
return IngestModule.ProcessResult.ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
MatOfRect detectionRectangles = new MatOfRect(); //the rectangles which reprent the coordinates on the image for where objects were detected
|
MatOfRect detectionRectangles = new MatOfRect(); //the rectangles which reprent the coordinates on the image for where objects were detected
|
||||||
for (String classifierKey : classifiers.keySet()) {
|
for (String classifierKey : classifiers.keySet()) {
|
||||||
//apply each classifier to the file
|
//apply each classifier to the file
|
||||||
@ -117,7 +129,11 @@ public class ObjectDetectectionFileIngestModule extends FileIngestModuleAdapter
|
|||||||
classifiers.get(classifierKey).detectMultiScale(originalImage, detectionRectangles);
|
classifiers.get(classifierKey).detectMultiScale(originalImage, detectionRectangles);
|
||||||
} catch (CvException ignored) {
|
} catch (CvException ignored) {
|
||||||
//The image was likely an image which we are unable to generate a thumbnail for, and the classifier was likely one where that is not acceptable
|
//The image was likely an image which we are unable to generate a thumbnail for, and the classifier was likely one where that is not acceptable
|
||||||
logger.log(Level.INFO, String.format("Classifier '%s' could not be applied to file '%s'.", classifierKey, file.getParentPath() + file.getName())); //NON-NLS
|
logger.log(Level.INFO, String.format("Classifier '%s' could not be applied to file '%s'.", classifierKey, file.getParentPath() + file.getName() + " with object id of " + file.getId())); //NON-NLS
|
||||||
|
continue;
|
||||||
|
} catch (Exception unexpectedException) {
|
||||||
|
//hopefully an unnecessary generic exception catch but currently present to catch any exceptions OpenCv throws which may not be documented
|
||||||
|
logger.log(Level.SEVERE, "Unexpected Exception encountered for image " + file.getParentPath() + file.getName() + " with object id of " + file.getId() +" while trying to apply classifier " + classifierKey, unexpectedException);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,8 +352,9 @@ public class GroupManager {
|
|||||||
case MIME_TYPE:
|
case MIME_TYPE:
|
||||||
if (nonNull(db)) {
|
if (nonNull(db)) {
|
||||||
HashSet<String> types = new HashSet<>();
|
HashSet<String> types = new HashSet<>();
|
||||||
|
|
||||||
// Use the group_concat function to get a list of files for each mime type.
|
// Use the group_concat function to get a list of files for each mime type.
|
||||||
// This has sifferent syntax on Postgres vs SQLite
|
// This has different syntax on Postgres vs SQLite
|
||||||
String groupConcatClause;
|
String groupConcatClause;
|
||||||
if (DbType.POSTGRESQL == controller.getSleuthKitCase().getDatabaseType()) {
|
if (DbType.POSTGRESQL == controller.getSleuthKitCase().getDatabaseType()) {
|
||||||
groupConcatClause = " array_to_string(array_agg(obj_id), ',') as object_ids";
|
groupConcatClause = " array_to_string(array_agg(obj_id), ',') as object_ids";
|
||||||
@ -361,8 +362,8 @@ public class GroupManager {
|
|||||||
else {
|
else {
|
||||||
groupConcatClause = " group_concat(obj_id) as object_ids";
|
groupConcatClause = " group_concat(obj_id) as object_ids";
|
||||||
}
|
}
|
||||||
String querySQL = "select " + groupConcatClause + ", mime_type from tsk_files group by mime_type ";
|
String query = "select " + groupConcatClause + " , mime_type from tsk_files group by mime_type ";
|
||||||
try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery(querySQL); //NON-NLS
|
try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery(query); //NON-NLS
|
||||||
ResultSet resultSet = executeQuery.getResultSet();) {
|
ResultSet resultSet = executeQuery.getResultSet();) {
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
final String mimeType = resultSet.getString("mime_type"); //NON-NLS
|
final String mimeType = resultSet.getString("mime_type"); //NON-NLS
|
||||||
|
@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
|||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
@ -48,7 +47,6 @@ import org.sleuthkit.datamodel.LayoutFile;
|
|||||||
import org.sleuthkit.datamodel.LocalFile;
|
import org.sleuthkit.datamodel.LocalFile;
|
||||||
import org.sleuthkit.datamodel.Report;
|
import org.sleuthkit.datamodel.Report;
|
||||||
import org.sleuthkit.datamodel.SlackFile;
|
import org.sleuthkit.datamodel.SlackFile;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
|
||||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,50 +124,45 @@ class AdHocSearchFilterNode extends FilterNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(File f) {
|
public List<Action> visit(File f) {
|
||||||
return getFileActions(true);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(DerivedFile f) {
|
public List<Action> visit(DerivedFile f) {
|
||||||
return getFileActions(true);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(Directory d) {
|
public List<Action> visit(Directory d) {
|
||||||
return getFileActions(false);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(LayoutFile lf) {
|
public List<Action> visit(LayoutFile lf) {
|
||||||
//we want hashsearch enabled on carved files but not unallocated blocks
|
return getFileActions();
|
||||||
boolean enableHashSearch = (lf.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.CARVED);
|
|
||||||
return getFileActions(enableHashSearch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(LocalFile lf) {
|
public List<Action> visit(LocalFile lf) {
|
||||||
return getFileActions(true);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(SlackFile f) {
|
public List<Action> visit(SlackFile f) {
|
||||||
return getFileActions(false);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(VirtualDirectory dir) {
|
public List<Action> visit(VirtualDirectory dir) {
|
||||||
return getFileActions(false);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Action> getFileActions(boolean enableHashSearch) {
|
private List<Action> getFileActions() {
|
||||||
List<Action> actionsList = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), AdHocSearchFilterNode.this));
|
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), AdHocSearchFilterNode.this));
|
||||||
actionsList.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal()));
|
actionsList.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal()));
|
||||||
actionsList.add(null);
|
actionsList.add(null);
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
Action hashSearchAction = new HashSearchAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.searchSameMd5"), getOriginal());
|
|
||||||
hashSearchAction.setEnabled(enableHashSearch);
|
|
||||||
actionsList.add(hashSearchAction);
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
@ -185,7 +178,7 @@ class AdHocSearchFilterNode extends FilterNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Action> defaultVisit(Content c) {
|
protected List<Action> defaultVisit(Content c) {
|
||||||
return getFileActions(false);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,8 +172,7 @@ abstract class AdHocSearchPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get dataSourceMap with object id and data source display name. Add the
|
* Get dataSourceMap with object id and data source display name.
|
||||||
* data source full name to toolTipList
|
|
||||||
*
|
*
|
||||||
* @return The list of data source name
|
* @return The list of data source name
|
||||||
*/
|
*/
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.keywordsearch;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.Component;
|
||||||
|
import java.awt.Cursor;
|
||||||
|
import java.awt.EventQueue;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.awt.event.MouseMotionListener;
|
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -32,7 +32,6 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.ListSelectionModel;
|
import javax.swing.ListSelectionModel;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
@ -667,11 +666,21 @@ class DropdownListSearchPanel extends AdHocSearchPanel {
|
|||||||
* Set the dataSourceList enabled if the dataSourceCheckBox is selected
|
* Set the dataSourceList enabled if the dataSourceCheckBox is selected
|
||||||
*/
|
*/
|
||||||
private void setComponentsEnabled() {
|
private void setComponentsEnabled() {
|
||||||
boolean enabled = this.dataSourceCheckBox.isSelected();
|
|
||||||
this.dataSourceList.setEnabled(enabled);
|
if (getDataSourceListModel().size() > 1) {
|
||||||
if (enabled) {
|
this.dataSourceCheckBox.setEnabled(true);
|
||||||
this.dataSourceList.setSelectionInterval(0, this.dataSourceList.getModel().getSize()-1);
|
|
||||||
|
boolean enabled = this.dataSourceCheckBox.isSelected();
|
||||||
|
this.dataSourceList.setEnabled(enabled);
|
||||||
|
if (enabled) {
|
||||||
|
this.dataSourceList.setSelectionInterval(0, this.dataSourceList.getModel().getSize()-1);
|
||||||
|
} else {
|
||||||
|
this.dataSourceList.setSelectedIndices(new int[0]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
this.dataSourceCheckBox.setEnabled(false);
|
||||||
|
this.dataSourceCheckBox.setSelected(false);
|
||||||
|
this.dataSourceList.setEnabled(false);
|
||||||
this.dataSourceList.setSelectedIndices(new int[0]);
|
this.dataSourceList.setSelectedIndices(new int[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,6 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.FocusListener;
|
import java.awt.event.FocusListener;
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.awt.event.MouseMotionListener;
|
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -32,7 +30,6 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
@ -374,18 +371,26 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel {
|
|||||||
}
|
}
|
||||||
setComponentsEnabled();
|
setComponentsEnabled();
|
||||||
firePropertyChange(Bundle.DropdownSingleTermSearchPanel_selected(), null, null);
|
firePropertyChange(Bundle.DropdownSingleTermSearchPanel_selected(), null, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the dataSourceList enabled if the dataSourceCheckBox is selected
|
* Set the dataSourceList enabled if the dataSourceCheckBox is selected
|
||||||
*/
|
*/
|
||||||
private void setComponentsEnabled() {
|
private void setComponentsEnabled() {
|
||||||
boolean enabled = this.dataSourceCheckBox.isSelected();
|
if (getDataSourceListModel().size() > 1) {
|
||||||
this.dataSourceList.setEnabled(enabled);
|
this.dataSourceCheckBox.setEnabled(true);
|
||||||
if (enabled) {
|
|
||||||
this.dataSourceList.setSelectionInterval(0, this.dataSourceList.getModel().getSize()-1);
|
boolean enabled = this.dataSourceCheckBox.isSelected();
|
||||||
|
this.dataSourceList.setEnabled(enabled);
|
||||||
|
if (enabled) {
|
||||||
|
this.dataSourceList.setSelectionInterval(0, this.dataSourceList.getModel().getSize()-1);
|
||||||
|
} else {
|
||||||
|
this.dataSourceList.setSelectedIndices(new int[0]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
this.dataSourceCheckBox.setEnabled(false);
|
||||||
|
this.dataSourceCheckBox.setSelected(false);
|
||||||
|
this.dataSourceList.setEnabled(false);
|
||||||
this.dataSourceList.setSelectedIndices(new int[0]);
|
this.dataSourceList.setSelectedIndices(new int[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ import org.openide.util.NbBundle;
|
|||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
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.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.ingest.FileIngestModule;
|
import org.sleuthkit.autopsy.ingest.FileIngestModule;
|
||||||
@ -92,6 +91,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
|||||||
private boolean startedSearching = false;
|
private boolean startedSearching = false;
|
||||||
private List<ContentTextExtractor> textExtractors;
|
private List<ContentTextExtractor> textExtractors;
|
||||||
private StringsTextExtractor stringExtractor;
|
private StringsTextExtractor stringExtractor;
|
||||||
|
private TextFileExtractor txtFileExtractor;
|
||||||
private final KeywordSearchJobSettings settings;
|
private final KeywordSearchJobSettings settings;
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
private long jobId;
|
private long jobId;
|
||||||
@ -244,6 +244,8 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
|||||||
stringExtractor.setScripts(KeywordSearchSettings.getStringExtractScripts());
|
stringExtractor.setScripts(KeywordSearchSettings.getStringExtractScripts());
|
||||||
stringExtractor.setOptions(KeywordSearchSettings.getStringExtractOptions());
|
stringExtractor.setOptions(KeywordSearchSettings.getStringExtractOptions());
|
||||||
|
|
||||||
|
txtFileExtractor = new TextFileExtractor();
|
||||||
|
|
||||||
textExtractors = new ArrayList<>();
|
textExtractors = new ArrayList<>();
|
||||||
//order matters, more specific extractors first
|
//order matters, more specific extractors first
|
||||||
textExtractors.add(new HtmlTextExtractor());
|
textExtractors.add(new HtmlTextExtractor());
|
||||||
@ -343,7 +345,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
|||||||
textExtractors.clear();
|
textExtractors.clear();
|
||||||
textExtractors = null;
|
textExtractors = null;
|
||||||
stringExtractor = null;
|
stringExtractor = null;
|
||||||
|
txtFileExtractor = null;
|
||||||
initialized = false;
|
initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,6 +570,17 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
|||||||
putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
|
putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((wasTextAdded == false) && (aFile.getNameExtension().equalsIgnoreCase("txt"))) {
|
||||||
|
try {
|
||||||
|
if (Ingester.getDefault().indexText(txtFileExtractor, aFile, context)) {
|
||||||
|
putIngestStatus(jobId, aFile.getId(), IngestStatus.TEXT_INGESTED);
|
||||||
|
wasTextAdded = true;
|
||||||
|
}
|
||||||
|
} catch (IngesterException ex) {
|
||||||
|
logger.log(Level.WARNING, "Unable to index as unicode", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if it wasn't supported or had an error, default to strings
|
// if it wasn't supported or had an error, default to strings
|
||||||
if (wasTextAdded == false) {
|
if (wasTextAdded == false) {
|
||||||
extractStringsAndIndex(aFile);
|
extractStringsAndIndex(aFile);
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 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.keywordsearch;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.apache.tika.parser.txt.CharsetDetector;
|
||||||
|
import org.apache.tika.parser.txt.CharsetMatch;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract text from .txt files
|
||||||
|
*/
|
||||||
|
final class TextFileExtractor extends ContentTextExtractor {
|
||||||
|
|
||||||
|
//Set a Minimum confidence value to reject matches that may not have a valid text encoding
|
||||||
|
//Values of valid text encodings were generally 100, xml code sometimes had a value around 50,
|
||||||
|
//and pictures and other files with a .txt extention were showing up with a value of 5 or less in limited testing.
|
||||||
|
//This limited information was used to select the current value as one that would filter out clearly non-text
|
||||||
|
//files while hopefully working on all files with a valid text encoding
|
||||||
|
static final private int MIN_MATCH_CONFIDENCE = 20;
|
||||||
|
static final private Logger logger = Logger.getLogger(TextFileExtractor.class.getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean isContentTypeSpecific() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean isSupported(Content file, String detectedFormat) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Reader getReader(Content source) throws TextExtractorException {
|
||||||
|
CharsetDetector detector = new CharsetDetector();
|
||||||
|
ReadContentInputStream stream = new ReadContentInputStream(source);
|
||||||
|
try {
|
||||||
|
detector.setText(stream);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new TextExtractorException("Unable to get string from detected text in UnicodeTextExtractor", ex);
|
||||||
|
}
|
||||||
|
CharsetMatch match = detector.detect();
|
||||||
|
if (match.getConfidence() < MIN_MATCH_CONFIDENCE) {
|
||||||
|
throw new TextExtractorException("Text does not match any character set with a high enough confidence for UnicodeTextExtractor");
|
||||||
|
}
|
||||||
|
|
||||||
|
return match.getReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDisabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logWarning(String msg, Exception ex) {
|
||||||
|
logger.log(Level.WARNING, msg, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -237,8 +237,19 @@ class SearchEngineURLQueryAnalyzer extends Extract {
|
|||||||
try { //try to decode the url
|
try { //try to decode the url
|
||||||
String decoded = URLDecoder.decode(x, "UTF-8"); //NON-NLS
|
String decoded = URLDecoder.decode(x, "UTF-8"); //NON-NLS
|
||||||
return decoded;
|
return decoded;
|
||||||
} catch (UnsupportedEncodingException uee) { //if it fails, return the encoded string
|
} catch (UnsupportedEncodingException exception) { //if it fails, return the encoded string
|
||||||
logger.log(Level.FINE, "Error during URL decoding ", uee); //NON-NLS
|
logger.log(Level.FINE, "Error during URL decoding, returning undecoded value:"
|
||||||
|
+ "\n\tURL: " + url
|
||||||
|
+ "\n\tUndecoded value: " + x
|
||||||
|
+ "\n\tEngine name: " + eng.getEngineName()
|
||||||
|
+ "\n\tEngine domain: " + eng.getDomainSubstring(), exception); //NON-NLS
|
||||||
|
return x;
|
||||||
|
} catch (IllegalArgumentException exception) { //if it fails, return the encoded string
|
||||||
|
logger.log(Level.SEVERE, "Illegal argument passed to URL decoding, returning undecoded value:"
|
||||||
|
+ "\n\tURL: " + url
|
||||||
|
+ "\n\tUndecoded value: " + x
|
||||||
|
+ "\n\tEngine name: " + eng.getEngineName()
|
||||||
|
+ "\n\tEngine domain: " + eng.getDomainSubstring(), exception); //NON-NLS)
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user