Merge branch 'develop' of https://github.com/sleuthkit/autopsy into image-gallery-db-migration
@ -64,13 +64,14 @@ public final class ReplaceBlackboardArtifactTagAction extends ReplaceTagAction<B
|
||||
*
|
||||
* @param oldArtifactTag tag to be replaced
|
||||
* @param newTagName name of the tag to replace with
|
||||
* @param comment the comment for the tag use an empty string for no comment
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"# {0} - old tag name",
|
||||
"# {1} - artifactID",
|
||||
"ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}."})
|
||||
@Override
|
||||
protected void replaceTag( BlackboardArtifactTag oldArtifactTag, TagName newTagName) {
|
||||
protected void replaceTag( BlackboardArtifactTag oldArtifactTag, TagName newTagName, String comment) {
|
||||
new SwingWorker<Void, Void>() {
|
||||
|
||||
@Override
|
||||
@ -90,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
|
||||
|
||||
tagsManager.deleteBlackboardArtifactTag(oldArtifactTag);
|
||||
tagsManager.addBlackboardArtifactTag(oldArtifactTag.getArtifact(), newTagName);
|
||||
tagsManager.addBlackboardArtifactTag(oldArtifactTag.getArtifact(), newTagName, comment);
|
||||
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
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",
|
||||
"ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}."})
|
||||
@Override
|
||||
protected void replaceTag(ContentTag oldTag, TagName newTagName) {
|
||||
protected void replaceTag(ContentTag oldTag, TagName newTagName, String comment) {
|
||||
new SwingWorker<Void, Void>() {
|
||||
|
||||
@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
|
||||
|
||||
tagsManager.deleteContentTag(oldTag);
|
||||
tagsManager.addContentTag(oldTag.getContent(), newTagName);
|
||||
tagsManager.addContentTag(oldTag.getContent(), newTagName, comment);
|
||||
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
||||
|
@ -77,10 +77,11 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
||||
/**
|
||||
* Method to actually replace the selected tag with the given new tag
|
||||
*
|
||||
* @param oldTag
|
||||
* @param newTagName
|
||||
* @param oldTag - the TagName which is being removed from the item
|
||||
* @param newTagName - the TagName which is being added to the itme
|
||||
* @param comment the comment associated with the tag, empty string for no comment
|
||||
*/
|
||||
abstract protected void replaceTag(T oldTag, TagName newTagName);
|
||||
abstract protected void replaceTag(T oldTag, TagName newTagName, String comment);
|
||||
|
||||
/**
|
||||
* Returns elected tags which are to be replaced
|
||||
@ -140,7 +141,7 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
||||
// Add action to replace the tag
|
||||
tagNameItem.addActionListener((ActionEvent event) -> {
|
||||
selectedTags.forEach((oldtag) -> {
|
||||
replaceTag(oldtag, entry.getValue());
|
||||
replaceTag(oldtag, entry.getValue(), "");
|
||||
});
|
||||
});
|
||||
|
||||
@ -177,12 +178,24 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
||||
TagName newTagName = GetTagNameDialog.doDialog();
|
||||
if (null != newTagName) {
|
||||
selectedTags.forEach((oldtag) -> {
|
||||
replaceTag(oldtag, newTagName);
|
||||
replaceTag(oldtag, newTagName, "");
|
||||
});
|
||||
}
|
||||
});
|
||||
add(newTagMenuItem);
|
||||
|
||||
// Create a "Choose Tag and Comment..." menu item. Selecting this item initiates
|
||||
// a dialog that can be used to create or select a tag name with an
|
||||
// optional comment and adds a tag with the resulting name.
|
||||
JMenuItem tagAndCommentItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.tagAndComment"));
|
||||
tagAndCommentItem.addActionListener((ActionEvent event) -> {
|
||||
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog();
|
||||
if (null != tagNameAndComment) {
|
||||
selectedTags.forEach((oldtag) -> {
|
||||
replaceTag(oldtag, tagNameAndComment.getTagName(), tagNameAndComment.getComment());
|
||||
});
|
||||
}
|
||||
});
|
||||
add(tagAndCommentItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import javax.swing.Box.Filler;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
@ -67,7 +68,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
}
|
||||
|
||||
|
||||
//add actionlistner to listen for change
|
||||
}
|
||||
|
||||
@ -132,7 +133,7 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
||||
//Add the button
|
||||
JToggleButton dspButton = createDspButton(dspType);
|
||||
dspButton.addActionListener(cbActionListener);
|
||||
if ((Case.getCurrentCaseThrows().getCaseType() == Case.CaseType.MULTI_USER_CASE) && dspType.equals(LocalDiskDSProcessor.getType())){
|
||||
if ((Case.getCurrentCaseThrows().getCaseType() == Case.CaseType.MULTI_USER_CASE) && dspType.equals(LocalDiskDSProcessor.getType())) {
|
||||
dspButton.setEnabled(false); //disable the button for local disk DSP when this is a multi user case
|
||||
dspButton.setSelected(false);
|
||||
shouldAddMultiUserWarning = true;
|
||||
@ -172,6 +173,9 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
||||
constraints.weighty = 1;
|
||||
gridBagLayout.setConstraints(vertGlue, constraints);
|
||||
jPanel1.setLayout(gridBagLayout);
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
jScrollPane1.getVerticalScrollBar().setValue(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -199,16 +199,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
||||
"DataContentViewerOtherCases.caseDetailsDialog.noCaseNameError=Error",
|
||||
"DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."})
|
||||
private void showCaseDetails(int selectedRowViewIdx) {
|
||||
Case openCase;
|
||||
try {
|
||||
openCase = Case.getCurrentCaseThrows();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
|
||||
Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(),
|
||||
Bundle.DataContentViewerOtherCases_noOpenCase_errMsg(),
|
||||
DEFAULT_OPTION, PLAIN_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError();
|
||||
try {
|
||||
if (-1 != selectedRowViewIdx) {
|
||||
@ -225,7 +216,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
||||
}
|
||||
caseDisplayName = eamCasePartial.getDisplayName();
|
||||
// query case details
|
||||
CorrelationCase eamCase = dbManager.getCase(openCase);
|
||||
CorrelationCase eamCase = dbManager.getCaseByUUID(eamCasePartial.getCaseUUID());
|
||||
if (eamCase == null) {
|
||||
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
|
||||
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
|
||||
@ -246,6 +237,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
||||
DEFAULT_OPTION, PLAIN_MESSAGE);
|
||||
}
|
||||
} catch (EamDbException ex) {
|
||||
logger.log(Level.SEVERE, "Error loading case details", ex);
|
||||
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
|
||||
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
|
||||
caseDisplayName,
|
||||
|
@ -38,7 +38,7 @@ import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil.updateSchemaVersion;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
@ -881,7 +881,7 @@ abstract class AbstractSqlEamDb implements EamDb {
|
||||
sql
|
||||
+= "+ (SELECT count(*) FROM "
|
||||
+ table_name
|
||||
+ " WHERE case_id=(SELECT id FROM cases WHERE case_uid=?) and data_source_id=(SELECT id FROM data_sources WHERE device_id=?))";
|
||||
+ " WHERE data_source_id=(SELECT data_sources.id FROM cases INNER JOIN data_sources ON cases.id = data_sources.case_id WHERE case_uid=? and device_id=?))";
|
||||
}
|
||||
|
||||
try {
|
||||
@ -1004,8 +1004,8 @@ abstract class AbstractSqlEamDb implements EamDb {
|
||||
bulkArtifacts.get(type.getDbTableName()).clear();
|
||||
}
|
||||
|
||||
TimingMetric timingMetric = EnterpriseHealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
|
||||
EnterpriseHealthMonitor.submitTimingMetric(timingMetric);
|
||||
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
|
||||
HealthMonitor.submitTimingMetric(timingMetric);
|
||||
|
||||
// Reset state
|
||||
bulkArtifactsCount = 0;
|
||||
|
@ -49,7 +49,7 @@ import org.sleuthkit.datamodel.HashUtility;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
|
||||
/**
|
||||
@ -135,9 +135,9 @@ final class IngestModule implements FileIngestModule {
|
||||
*/
|
||||
if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) {
|
||||
try {
|
||||
TimingMetric timingMetric = EnterpriseHealthMonitor.getTimingMetric("Correlation Engine: Notable artifact query");
|
||||
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Notable artifact query");
|
||||
List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(timingMetric);
|
||||
HealthMonitor.submitTimingMetric(timingMetric);
|
||||
if (!caseDisplayNamesList.isEmpty()) {
|
||||
postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList);
|
||||
}
|
||||
|
@ -29,9 +29,9 @@
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="0" pref="4" max="32767" attributes="0"/>
|
||||
<Component id="showCasesPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="4" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Component id="showCasesPanel" pref="1188" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
@ -43,9 +43,9 @@
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="0" pref="6" max="32767" attributes="0"/>
|
||||
<Component id="showCasesPanel" min="-2" pref="426" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Component id="showCasesPanel" pref="473" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@ -63,7 +63,7 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="527" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="1188" max="32767" attributes="0"/>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Component id="showCasesScrollPane" alignment="0" pref="527" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
@ -71,7 +71,7 @@
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="426" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="473" max="32767" attributes="0"/>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Component id="showCasesScrollPane" alignment="0" pref="407" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
@ -94,20 +94,17 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="1222" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="1423" max="32767" attributes="0"/>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="innerCaseScrollPane" min="-2" pref="1222" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="innerCaseScrollPane" alignment="0" pref="1423" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="400" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="500" max="32767" attributes="0"/>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Component id="innerCaseScrollPane" alignment="0" pref="400" max="32767" attributes="0"/>
|
||||
<Component id="innerCaseScrollPane" alignment="0" pref="500" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
|
@ -107,17 +107,15 @@ final class ShowCasesDialog extends JDialog {
|
||||
outCasesPane.setLayout(outCasesPaneLayout);
|
||||
outCasesPaneLayout.setHorizontalGroup(
|
||||
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 1222, Short.MAX_VALUE)
|
||||
.addGap(0, 1423, Short.MAX_VALUE)
|
||||
.addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(outCasesPaneLayout.createSequentialGroup()
|
||||
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 1222, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, Short.MAX_VALUE)))
|
||||
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1423, Short.MAX_VALUE))
|
||||
);
|
||||
outCasesPaneLayout.setVerticalGroup(
|
||||
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 400, Short.MAX_VALUE)
|
||||
.addGap(0, 500, Short.MAX_VALUE)
|
||||
.addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE))
|
||||
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
showCasesScrollPane.setViewportView(outCasesPane);
|
||||
@ -126,13 +124,13 @@ final class ShowCasesDialog extends JDialog {
|
||||
showCasesPanel.setLayout(showCasesPanelLayout);
|
||||
showCasesPanelLayout.setHorizontalGroup(
|
||||
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 527, Short.MAX_VALUE)
|
||||
.addGap(0, 1188, Short.MAX_VALUE)
|
||||
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 527, Short.MAX_VALUE))
|
||||
);
|
||||
showCasesPanelLayout.setVerticalGroup(
|
||||
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 407, Short.MAX_VALUE)
|
||||
.addGap(0, 473, Short.MAX_VALUE)
|
||||
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 407, Short.MAX_VALUE))
|
||||
);
|
||||
@ -150,9 +148,9 @@ final class ShowCasesDialog extends JDialog {
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(0, 4, Short.MAX_VALUE)
|
||||
.addComponent(showCasesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 4, Short.MAX_VALUE))
|
||||
.addGap(6, 6, 6)
|
||||
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1188, Short.MAX_VALUE)
|
||||
.addGap(6, 6, 6))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(closeButton)
|
||||
@ -161,9 +159,9 @@ final class ShowCasesDialog extends JDialog {
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(0, 6, Short.MAX_VALUE)
|
||||
.addComponent(showCasesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 426, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGap(6, 6, 6)
|
||||
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 473, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(closeButton)
|
||||
.addContainerGap())
|
||||
);
|
||||
|
@ -20,13 +20,14 @@
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import java.util.Map;
|
||||
import org.sleuthkit.datamodel.TskData.FileKnown;
|
||||
|
||||
/**
|
||||
* Provides logic for selecting common files from all data sources.
|
||||
*/
|
||||
final public class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadataBuilder {
|
||||
|
||||
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where (known != 1 OR known IS NULL)%s GROUP BY md5 HAVING COUNT(*) > 1) order by md5"; //NON-NLS
|
||||
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where (known != "+ FileKnown.KNOWN.getFileKnownValue() + " OR known IS NULL)%s GROUP BY md5 HAVING COUNT(DISTINCT data_source_obj_id) > 1) order by md5"; //NON-NLS
|
||||
|
||||
/**
|
||||
* Implements the algorithm for getting common files across all data
|
||||
|
@ -7,7 +7,7 @@ CommonFilesPanel.selectedFileCategoriesButton.text=Match on the following file c
|
||||
CommonFilesPanel.selectedFileCategoriesButton.toolTipText=Select from the options below...
|
||||
CommonFilesPanel.pictureVideoCheckbox.text=Pictures and Videos
|
||||
CommonFilesPanel.documentsCheckbox.text=Documents
|
||||
CommonFilesPanel.commonFilesSearchLabel.text=<html>Find duplicate files in the current case.</html>
|
||||
CommonFilesPanel.commonFilesSearchLabel.text=<html>Find files in multiple data sources in the current case.</html>
|
||||
CommonFilesPanel.allFileCategoriesRadioButton.toolTipText=No filtering applied to results...
|
||||
CommonFilesPanel.allFileCategoriesRadioButton.text=Match on all file types
|
||||
CommonFilesPanel.text=Indicate which data sources to consider while searching for duplicates:
|
||||
|
@ -20,6 +20,7 @@
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -28,14 +29,15 @@ import java.util.Map;
|
||||
*/
|
||||
final public class CommonFilesMetadata {
|
||||
|
||||
private final Map<String, Md5Metadata> metadata;
|
||||
|
||||
private final Map<Integer, List<Md5Metadata>> metadata;
|
||||
|
||||
/**
|
||||
* Create meta dat object which can be handed off to the node factories
|
||||
*
|
||||
* @param metadata map of md5 to parent-level node meta data
|
||||
* Create a metadata object which can be handed off to the node
|
||||
* factories.
|
||||
*
|
||||
* @param metadata list of Md5Metadata indexed by size of Md5Metadata
|
||||
*/
|
||||
CommonFilesMetadata(Map<String, Md5Metadata> metadata) {
|
||||
CommonFilesMetadata(Map<Integer, List<Md5Metadata>> metadata){
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@ -48,11 +50,11 @@ final public class CommonFilesMetadata {
|
||||
* @param md5 key
|
||||
* @return
|
||||
*/
|
||||
Md5Metadata getMetadataForMd5(String md5) {
|
||||
return this.metadata.get(md5);
|
||||
List<Md5Metadata> getMetadataForMd5(Integer instanceCount) {
|
||||
return this.metadata.get(instanceCount);
|
||||
}
|
||||
|
||||
public Map<String, Md5Metadata> getMetadata() {
|
||||
public Map<Integer, List<Md5Metadata>> getMetadata() {
|
||||
return Collections.unmodifiableMap(this.metadata);
|
||||
}
|
||||
|
||||
@ -61,9 +63,12 @@ final public class CommonFilesMetadata {
|
||||
* @return number of file instances
|
||||
*/
|
||||
public int size() {
|
||||
|
||||
int count = 0;
|
||||
for (Md5Metadata data : this.metadata.values()) {
|
||||
count += data.size();
|
||||
for (List<Md5Metadata> data : this.metadata.values()) {
|
||||
for(Md5Metadata md5 : data){
|
||||
count += md5.size();
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.openide.util.NbBundle;
|
||||
@ -51,7 +52,7 @@ public abstract class CommonFilesMetadataBuilder {
|
||||
private final Map<Long, String> dataSourceIdToNameMap;
|
||||
private final boolean filterByMedia;
|
||||
private final boolean filterByDoc;
|
||||
private static final String filterByMimeTypesWhereClause = " and mime_type in (%s)"; //NON-NLS // where %s is csv list of mime_types to filter on
|
||||
private static final String FILTER_BY_MIME_TYPES_WHERE_CLAUSE = " and mime_type in (%s)"; //NON-NLS // where %s is csv list of mime_types to filter on
|
||||
|
||||
/*
|
||||
* The set of the MIME types that will be checked for extension mismatches
|
||||
@ -198,8 +199,22 @@ public abstract class CommonFilesMetadataBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<Integer, List<Md5Metadata>> instanceCollatedCommonFiles = new TreeMap<>();
|
||||
|
||||
return new CommonFilesMetadata(commonFiles);
|
||||
for(Md5Metadata md5Metadata : commonFiles.values()){
|
||||
Integer size = md5Metadata.size();
|
||||
|
||||
if(instanceCollatedCommonFiles.containsKey(size)){
|
||||
instanceCollatedCommonFiles.get(size).add(md5Metadata);
|
||||
} else {
|
||||
ArrayList<Md5Metadata> value = new ArrayList<>();
|
||||
value.add(md5Metadata);
|
||||
instanceCollatedCommonFiles.put(size, value);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommonFilesMetadata(instanceCollatedCommonFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,7 +243,7 @@ public abstract class CommonFilesMetadataBuilder {
|
||||
mimeTypeFilter.append("'").append(mimeType).append("',");
|
||||
}
|
||||
mimeTypeString = mimeTypeFilter.toString().substring(0, mimeTypeFilter.length() - 1);
|
||||
mimeTypeString = String.format(filterByMimeTypesWhereClause, new Object[]{mimeTypeString});
|
||||
mimeTypeString = String.format(FILTER_BY_MIME_TYPES_WHERE_CLAUSE, new Object[]{mimeTypeString});
|
||||
}
|
||||
return mimeTypeString;
|
||||
}
|
||||
|
@ -23,20 +23,18 @@ import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.datamodel.Md5Node;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
|
||||
/**
|
||||
* Wrapper node for <code>Md5Node</code> used to display common files search
|
||||
* results in the top right pane. Calls <code>Md5NodeFactory</code>.
|
||||
* results in the top right pane. Calls <code>InstanceCountNodeFactory</code>.
|
||||
*/
|
||||
final public class CommonFilesNode extends DisplayableItemNode {
|
||||
|
||||
|
||||
CommonFilesNode(CommonFilesMetadata metadataList) {
|
||||
super(Children.create(new Md5NodeFactory(metadataList), true), Lookups.singleton(CommonFilesNode.class));
|
||||
super(Children.create(new InstanceCountNodeFactory(metadataList), true));
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
@ -60,37 +58,33 @@ final public class CommonFilesNode extends DisplayableItemNode {
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ChildFactory which builds CommonFileParentNodes from the
|
||||
* CommonFilesMetaaData models.
|
||||
* Used to generate <code>InstanceCountNode</code>s.
|
||||
*/
|
||||
static class Md5NodeFactory extends ChildFactory<String> {
|
||||
static class InstanceCountNodeFactory extends ChildFactory<Integer>{
|
||||
|
||||
private final CommonFilesMetadata metadata;
|
||||
|
||||
/**
|
||||
* List of models, each of which is a parent node matching a single md5,
|
||||
* containing children FileNodes.
|
||||
* Build a factory which converts a <code>CommonFilesMetadata</code>
|
||||
* object into <code>DisplayableItemNode</code>s.
|
||||
* @param metadata
|
||||
*/
|
||||
private CommonFilesMetadata metadata;
|
||||
|
||||
Md5NodeFactory(CommonFilesMetadata metadata) {
|
||||
InstanceCountNodeFactory(CommonFilesMetadata metadata){
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
protected void removeNotify() {
|
||||
metadata = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(String md5){
|
||||
Md5Metadata metadata = this.metadata.getMetadataForMd5(md5);
|
||||
return new Md5Node(metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<String> list) {
|
||||
protected boolean createKeys(List<Integer> list) {
|
||||
list.addAll(this.metadata.getMetadata().keySet());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Integer instanceCount){
|
||||
List<Md5Metadata> md5Metadata = this.metadata.getMetadataForMd5(instanceCount);
|
||||
return new InstanceCountNode(instanceCount, md5Metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,12 +104,15 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
|
||||
CommonFilesPanel.this.selectDataSourceComboBox.setModel(CommonFilesPanel.this.dataSourcesList);
|
||||
|
||||
boolean multipleDataSources = this.caseHasMultipleSources();
|
||||
CommonFilesPanel.this.allDataSourcesRadioButton.setEnabled(multipleDataSources);
|
||||
CommonFilesPanel.this.allDataSourcesRadioButton.setSelected(multipleDataSources);
|
||||
|
||||
|
||||
CommonFilesPanel.this.allDataSourcesRadioButton.setEnabled(true);
|
||||
CommonFilesPanel.this.allDataSourcesRadioButton.setSelected(true);
|
||||
|
||||
if (!multipleDataSources) {
|
||||
CommonFilesPanel.this.withinDataSourceRadioButton.setSelected(true);
|
||||
withinDataSourceSelected(true);
|
||||
CommonFilesPanel.this.withinDataSourceRadioButton.setEnabled(false);
|
||||
CommonFilesPanel.this.withinDataSourceRadioButton.setSelected(false);
|
||||
withinDataSourceSelected(false);
|
||||
CommonFilesPanel.this.selectDataSourceComboBox.setEnabled(false);
|
||||
}
|
||||
|
||||
CommonFilesPanel.this.searchButton.setEnabled(true);
|
||||
@ -120,7 +123,7 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
private boolean caseHasMultipleSources() {
|
||||
return CommonFilesPanel.this.dataSourceMap.size() >= 2;
|
||||
return CommonFilesPanel.this.dataSourceMap.size() >= 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -250,11 +253,12 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
|
||||
|
||||
CommonFilesNode commonFilesNode = new CommonFilesNode(metadata);
|
||||
|
||||
//TODO this could be enumerating the children!!!
|
||||
DataResultFilterNode dataResultFilterNode = new DataResultFilterNode(commonFilesNode, ExplorerManager.find(CommonFilesPanel.this));
|
||||
|
||||
TableFilterNode tableFilterWithDescendantsNode = new TableFilterNode(dataResultFilterNode);
|
||||
TableFilterNode tableFilterWithDescendantsNode = new TableFilterNode(dataResultFilterNode, 3);
|
||||
|
||||
DataResultViewerTable table = new DataResultViewerTable();
|
||||
DataResultViewerTable table = new CommonFilesSearchResultsViewerTable();
|
||||
|
||||
Collection<DataResultViewer> viewers = new ArrayList<>(1);
|
||||
viewers.add(table);
|
||||
|
@ -19,11 +19,14 @@
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.core.Installer;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* Encapsulates a menu action which triggers the common files search dialog.
|
||||
@ -32,15 +35,22 @@ final public class CommonFilesSearchAction extends CallableSystemAction {
|
||||
|
||||
private static CommonFilesSearchAction instance = null;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CommonFilesSearchAction.class.getName());
|
||||
|
||||
CommonFilesSearchAction() {
|
||||
super();
|
||||
this.setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(){
|
||||
return super.isEnabled() && Case.isCaseOpen() && Installer.isJavaFxInited();
|
||||
boolean shouldBeEnabled = false;
|
||||
try {
|
||||
shouldBeEnabled = Case.isCaseOpen() && Case.getCurrentCase().getDataSources().size() > 1;
|
||||
} catch(TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting data sources for action enabled check", ex);
|
||||
}
|
||||
return super.isEnabled() && shouldBeEnabled;
|
||||
}
|
||||
|
||||
public static synchronized CommonFilesSearchAction getDefault() {
|
||||
|
@ -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.commonfilesearch;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||
|
||||
/**
|
||||
* <code>DataResultViewerTable</code> which overrides the default column
|
||||
* header width calculations. The <code>CommonFilesSearchResultsViewerTable</code>
|
||||
* 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
|
||||
* rows and looking for wide cells. Rather, we just pick some reasonable values.
|
||||
*/
|
||||
public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
||||
|
||||
private static final Map<String, Integer> COLUMN_WIDTHS;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
static {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), 260);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), 65);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), 300);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), 200);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), 100);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), 130);
|
||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_tagsColLbl1(), 300);
|
||||
|
||||
COLUMN_WIDTHS = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"CommonFilesSearchResultsViewerTable.filesColLbl=Files",
|
||||
"CommonFilesSearchResultsViewerTable.instancesColLbl=Instances",
|
||||
"CommonFilesSearchResultsViewerTable.pathColLbl=Parent Path",
|
||||
"CommonFilesSearchResultsViewerTable.hashsetHitsColLbl=Hash Set Hits",
|
||||
"CommonFilesSearchResultsViewerTable.dataSourceColLbl=Data Source(s)",
|
||||
"CommonFilesSearchResultsViewerTable.mimeTypeColLbl=MIME Type",
|
||||
"CommonFilesSearchResultsViewerTable.tagsColLbl1=Tags"
|
||||
})
|
||||
@Override
|
||||
protected void setColumnWidths(){
|
||||
TableColumnModel model = this.getColumnModel();
|
||||
|
||||
Enumeration<TableColumn> columnsEnumerator = model.getColumns();
|
||||
while(columnsEnumerator.hasMoreElements()){
|
||||
|
||||
TableColumn column = columnsEnumerator.nextElement();
|
||||
|
||||
final String headerValue = column.getHeaderValue().toString();
|
||||
final Integer get = COLUMN_WIDTHS.get(headerValue);
|
||||
|
||||
column.setPreferredWidth(get);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.commonfilesearch;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
* Used by the Common Files search feature to encapsulate instances of a given
|
||||
MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
|
||||
*/
|
||||
public class FileInstanceNode extends FileNode {
|
||||
|
||||
private final String dataSource;
|
||||
|
||||
/**
|
||||
* Create a node which can be used in a multilayer tree table and is based
|
||||
* on an <code>AbstractFile</code>.
|
||||
*
|
||||
* @param fsContent
|
||||
* @param dataSource
|
||||
*/
|
||||
public FileInstanceNode(AbstractFile fsContent, String dataSource) {
|
||||
super(fsContent);
|
||||
this.dataSource = dataSource;
|
||||
|
||||
this.setDisplayName(fsContent.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode(){
|
||||
//Not used atm - could maybe be leveraged for better use in Children objects
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
String getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"FileInstanceNode.createSheet.noDescription= "})
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet sheet = new Sheet();
|
||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||
if (sheetSet == null) {
|
||||
sheetSet = Sheet.createPropertiesSet();
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
final String NO_DESCR = Bundle.FileInstanceNode_createSheet_noDescription();
|
||||
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsForFile(this.getContent())));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource()));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType())));
|
||||
|
||||
this.addTagProperty(sheetSet);
|
||||
|
||||
return sheet;
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
|
||||
/**
|
||||
* Node used to indicate the number of matches found with the MD5 children
|
||||
* of this Node.
|
||||
*/
|
||||
final public class InstanceCountNode extends DisplayableItemNode {
|
||||
|
||||
final private int instanceCount;
|
||||
final private List<Md5Metadata> metadataList;
|
||||
|
||||
/**
|
||||
* Create a node with the given number of instances, and the given
|
||||
* selection of metadata.
|
||||
* @param instanceCount
|
||||
* @param md5Metadata
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"InstanceCountNode.displayName=Files with %s instances (%s)"
|
||||
})
|
||||
public InstanceCountNode(int instanceCount, List<Md5Metadata> md5Metadata) {
|
||||
super(Children.create(new Md5NodeFactory(md5Metadata), true));
|
||||
|
||||
this.instanceCount = instanceCount;
|
||||
this.metadataList = md5Metadata;
|
||||
|
||||
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), md5Metadata.size()));
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of matches found for each of the MD5 children.
|
||||
* @return int match count
|
||||
*/
|
||||
int getInstanceCount() {
|
||||
return this.instanceCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of metadata for the MD5s which are children of this object.
|
||||
* @return List<Md5Metadata>
|
||||
*/
|
||||
List<Md5Metadata> getMetadata() {
|
||||
return Collections.unmodifiableList(this.metadataList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"InstanceCountNode.createSheet.noDescription= "})
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet sheet = new Sheet();
|
||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||
if (sheetSet == null) {
|
||||
sheetSet = Sheet.createPropertiesSet();
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
final String NO_DESCR = Bundle.InstanceCountNode_createSheet_noDescription();
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, ""));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), NO_DESCR, this.getInstanceCount()));
|
||||
return sheet;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ChildFactory which builds CommonFileParentNodes from the
|
||||
* CommonFilesMetaaData models.
|
||||
*/
|
||||
static class Md5NodeFactory extends ChildFactory<String> {
|
||||
|
||||
/**
|
||||
* List of models, each of which is a parent node matching a single md5,
|
||||
* containing children FileNodes.
|
||||
*/
|
||||
private final Map<String, Md5Metadata> metadata;
|
||||
|
||||
Md5NodeFactory(List<Md5Metadata> metadata) {
|
||||
this.metadata = new HashMap<>();
|
||||
|
||||
Iterator<Md5Metadata> iterator = metadata.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Md5Metadata md5Metadata = iterator.next();
|
||||
this.metadata.put(md5Metadata.getMd5(), md5Metadata);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(String md5) {
|
||||
Md5Metadata md5Metadata = this.metadata.get(md5);
|
||||
return new Md5Node(md5Metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<String> list) {
|
||||
list.addAll(this.metadata.keySet());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,23 +17,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceMetadata;
|
||||
import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
@ -52,30 +50,50 @@ public class Md5Node extends DisplayableItemNode {
|
||||
private final int commonFileCount;
|
||||
private final String dataSources;
|
||||
|
||||
@NbBundle.Messages({
|
||||
"Md5Node.Md5Node.format=MD5: %s"
|
||||
})
|
||||
/**
|
||||
* Create a Match node whose children will all have this object in common.
|
||||
* @param data the common feature, and the children
|
||||
*/
|
||||
public Md5Node(Md5Metadata data) {
|
||||
super(Children.create(
|
||||
new FileInstanceNodeFactory(data), true),
|
||||
Lookups.singleton(data.getMd5()));
|
||||
new FileInstanceNodeFactory(data), true));
|
||||
|
||||
this.commonFileCount = data.size();
|
||||
this.dataSources = String.join(", ", data.getDataSources());
|
||||
this.md5Hash = data.getMd5();
|
||||
|
||||
this.setDisplayName(this.md5Hash);
|
||||
|
||||
this.setDisplayName(String.format(Bundle.Md5Node_Md5Node_format(), this.md5Hash));
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* How many files are in common? This will be the number of children.
|
||||
* @return int
|
||||
*/
|
||||
int getCommonFileCount() {
|
||||
return this.commonFileCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Datasources where these matches occur.
|
||||
* @return string delimited list of sources
|
||||
*/
|
||||
String getDataSources() {
|
||||
return this.dataSources;
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 which is common to these matches
|
||||
* @return string md5 hash
|
||||
*/
|
||||
public String getMd5() {
|
||||
return this.md5Hash;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"Md5Node.createSheet.noDescription= "})
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet sheet = new Sheet();
|
||||
@ -85,30 +103,15 @@ public class Md5Node extends DisplayableItemNode {
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
fillPropertyMap(map, this);
|
||||
|
||||
final String NO_DESCR = Bundle.AbstractFsContentNode_noDesc_text();
|
||||
for (Md5Node.CommonFileParentPropertyType propType : Md5Node.CommonFileParentPropertyType.values()) {
|
||||
final String propString = propType.toString();
|
||||
sheetSet.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
|
||||
}
|
||||
final String NO_DESCR = Bundle.Md5Node_createSheet_noDescription();
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, ""));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, ""));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, ""));
|
||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSources()));
|
||||
|
||||
return sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill map with AbstractFile properties
|
||||
*
|
||||
* @param map map with preserved ordering, where property names/values are
|
||||
* put
|
||||
* @param node The item to get properties for.
|
||||
*/
|
||||
static private void fillPropertyMap(Map<String, Object> map, Md5Node node) {
|
||||
map.put(CommonFileParentPropertyType.File.toString(), node.getMd5());
|
||||
map.put(CommonFileParentPropertyType.InstanceCount.toString(), node.getCommonFileCount());
|
||||
map.put(CommonFileParentPropertyType.DataSource.toString(), node.getDataSources());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||
@ -144,9 +147,7 @@ public class Md5Node extends DisplayableItemNode {
|
||||
AbstractFile abstractFile = tskDb.findAllFilesWhere(String.format("obj_id in (%s)", file.getObjectId())).get(0);
|
||||
|
||||
return new FileInstanceNode(abstractFile, file.getDataSourceName());
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, String.format("Unable to create node for file with obj_id: %s.", new Object[]{file.getObjectId()}), ex);
|
||||
} catch (TskCoreException ex) {
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, String.format("Unable to create node for file with obj_id: %s.", new Object[]{file.getObjectId()}), ex);
|
||||
}
|
||||
return null;
|
||||
@ -159,25 +160,4 @@ public class Md5Node extends DisplayableItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"CommonFileParentPropertyType.fileColLbl=File",
|
||||
"CommonFileParentPropertyType.instanceColLbl=Instance Count",
|
||||
"CommonFileParentPropertyType.dataSourceColLbl=Data Source"})
|
||||
public enum CommonFileParentPropertyType {
|
||||
|
||||
File(Bundle.CommonFileParentPropertyType_fileColLbl()),
|
||||
InstanceCount(Bundle.CommonFileParentPropertyType_instanceColLbl()),
|
||||
DataSource(Bundle.CommonFileParentPropertyType_dataSourceColLbl());
|
||||
|
||||
final private String displayString;
|
||||
|
||||
private CommonFileParentPropertyType(String displayString) {
|
||||
this.displayString = displayString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,13 +20,14 @@
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import java.util.Map;
|
||||
import org.sleuthkit.datamodel.TskData.FileKnown;
|
||||
|
||||
/**
|
||||
* Provides logic for selecting common files from a single data source.
|
||||
*/
|
||||
final public class SingleDataSource extends CommonFilesMetadataBuilder {
|
||||
|
||||
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where md5 in (select md5 from tsk_files where (known != 1 OR known IS NULL) and data_source_obj_id=%s%s) GROUP BY md5 HAVING COUNT(*) > 1) order by md5"; //NON-NLS
|
||||
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where md5 in (select md5 from tsk_files where (known != "+ FileKnown.KNOWN.getFileKnownValue() + " OR known IS NULL) and data_source_obj_id=%s%s) GROUP BY md5 HAVING COUNT(DISTINCT data_source_obj_id) > 1) order by md5"; //NON-NLS
|
||||
private final Long selectedDataSourceId;
|
||||
private final String dataSourceName;
|
||||
|
||||
|
@ -486,7 +486,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID())
|
||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())
|
||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())
|
||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID())) {
|
||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID())
|
||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID())) {
|
||||
return 3;
|
||||
} else {
|
||||
return 6;
|
||||
|
@ -28,7 +28,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
* but the initial method was needed only be viewers in
|
||||
* corecomponents and therefore can stay out of public API.
|
||||
*/
|
||||
class DataContentViewerUtility {
|
||||
public class DataContentViewerUtility {
|
||||
/**
|
||||
* Returns the first non-Blackboard Artifact from a Node.
|
||||
* Needed for (at least) Hex and Strings that want to view
|
||||
@ -39,7 +39,7 @@ class DataContentViewerUtility {
|
||||
* @param node Node passed into content viewer
|
||||
* @return highest priority content or null if there is no content
|
||||
*/
|
||||
static Content getDefaultContent(Node node) {
|
||||
public static Content getDefaultContent(Node node) {
|
||||
Content bbContentSeen = null;
|
||||
for (Content content : (node).getLookup().lookupAll(Content.class)) {
|
||||
if (content instanceof BlackboardArtifact) {
|
||||
|
@ -78,7 +78,7 @@ import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
|
||||
*/
|
||||
@ServiceProvider(service = DataResultViewer.class)
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
public final class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(DataResultViewerTable.class.getName());
|
||||
@ -144,7 +144,6 @@ public final class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
outline = outlineView.getOutline();
|
||||
outline.setRowSelectionAllowed(true);
|
||||
outline.setColumnSelectionAllowed(true);
|
||||
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
outline.setRootVisible(false);
|
||||
outline.setDragEnabled(false);
|
||||
@ -180,6 +179,7 @@ public final class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
/**
|
||||
* Gets the title of this tabular result viewer.
|
||||
* @return title of tab.
|
||||
*/
|
||||
@Override
|
||||
@NbBundle.Messages("DataResultViewerTable.title=Table")
|
||||
@ -365,7 +365,7 @@ public final class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
* Sets the column widths for the child OutlineView of this tabular results
|
||||
* viewer.
|
||||
*/
|
||||
private void setColumnWidths() {
|
||||
protected void setColumnWidths() {
|
||||
if (rootNode.getChildren().getNodesCount() != 0) {
|
||||
final Graphics graphics = outlineView.getGraphics();
|
||||
if (graphics != null) {
|
||||
@ -401,6 +401,10 @@ public final class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
outline.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||
}
|
||||
}
|
||||
|
||||
protected TableColumnModel getColumnModel(){
|
||||
return outline.getColumnModel();
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets up the columns for the child OutlineView of this tabular results
|
||||
|
31
Core/src/org/sleuthkit/autopsy/corecomponents/GSTVideoPanel.java
Executable file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.corecomponents;
|
||||
|
||||
/**
|
||||
* This class exists to support backwards compatibility of an erroneous call to
|
||||
* Logger.getLogger(GSTVideoPanel.class.getName()) in OpenCVFrameCapture.java in
|
||||
* an older version of the Video Triage Net Beans Module (NBM). It should be
|
||||
* removed when we are ready to stop supporting older Video Triage NBMs. The
|
||||
* current Video Triage code has already been updated.
|
||||
*/
|
||||
@Deprecated
|
||||
public class GSTVideoPanel {
|
||||
|
||||
}
|
@ -23,29 +23,28 @@ import org.openide.nodes.FilterNode;
|
||||
import org.openide.nodes.Node;
|
||||
|
||||
/**
|
||||
* A Children implementation for a TableFilterNode. A TableFilterNode creates at
|
||||
* most one layer of child nodes for the node it wraps. It is designed to be
|
||||
* used in the results view to ensure the individual viewers display only the
|
||||
* first layer of child nodes.
|
||||
* A <code>Children</code> implementation for a
|
||||
* <code>TableFilterNode</code>. A
|
||||
* <code>TableFilterNode</code> creates at most one layer of child
|
||||
* nodes for the node it wraps. It is designed to be used in the results view
|
||||
* to ensure the individual viewers display only the first layer of child nodes.
|
||||
*/
|
||||
class TableFilterChildren extends FilterNode.Children {
|
||||
|
||||
/**
|
||||
* Creates a Children object for a TableFilterNode. A TableFilterNode
|
||||
* creates at most one layer of child nodes for the node it wraps. It is
|
||||
* designed to be used in the results view to ensure the individual viewers
|
||||
* display only the first layer of child nodes.
|
||||
creates at most one layer of child nodes for the node it wraps. It is
|
||||
designed to be used in the results view to ensure the individual viewers
|
||||
display only the first layer of child nodes.
|
||||
*
|
||||
*
|
||||
* @param wrappedNode The node wrapped by the TableFilterNode.
|
||||
* @param wrappedNode The node wrapped by the TableFilterNode.
|
||||
* @param createChildren True if a children (child factory) object should be
|
||||
* created for the wrapped node.
|
||||
* created for the wrapped node.
|
||||
*
|
||||
* @return A children (child factory) object for a node wrapped by a
|
||||
* TableFilterNode.
|
||||
* @return A children (child factory) object for a node wrapped by a TableFilterNode.
|
||||
*/
|
||||
public static Children createInstance(Node wrappedNode, boolean createChildren) {
|
||||
|
||||
|
||||
if (createChildren) {
|
||||
return new TableFilterChildren(wrappedNode);
|
||||
} else {
|
||||
@ -54,9 +53,10 @@ class TableFilterChildren extends FilterNode.Children {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a children (child factory) implementation for a
|
||||
* TableFilterNode. A TableFilterNode creates at most one layer of child
|
||||
* nodes for the node it wraps. It is designed to be used for nodes
|
||||
* Constructs a children (child factory) implementation for a
|
||||
* <code>TableFilterNode</code>. A
|
||||
* <code>TableFilterNode</code> creates at most one layer of
|
||||
* child nodes for the node it wraps. It is designed to be used for nodes
|
||||
* displayed in Autopsy table views.
|
||||
*
|
||||
* @param wrappedNode The node wrapped by the TableFilterNode.
|
||||
@ -64,10 +64,10 @@ class TableFilterChildren extends FilterNode.Children {
|
||||
TableFilterChildren(Node wrappedNode) {
|
||||
super(wrappedNode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies a TableFilterNode, with the create children (child factory) flag
|
||||
* set to false.
|
||||
* Copies a TableFilterNode, with the create children
|
||||
(child factory) flag set to false.
|
||||
*
|
||||
* @param nodeToCopy The TableFilterNode to copy.
|
||||
*
|
||||
@ -90,5 +90,4 @@ class TableFilterChildren extends FilterNode.Children {
|
||||
protected Node[] createNodes(Node key) {
|
||||
return new Node[]{this.copyNode(key)};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,21 +27,39 @@ import org.openide.nodes.Node;
|
||||
* of rows (plus/minus buttons for each row with children).
|
||||
*/
|
||||
final class TableFilterChildrenWithDescendants extends TableFilterChildren {
|
||||
|
||||
private TableFilterChildrenWithDescendants(Node wrappedNode) {
|
||||
|
||||
private final int childLayerDepth;
|
||||
|
||||
/**
|
||||
* Used to create children of the given node, with the specified number of
|
||||
* child generations.
|
||||
*
|
||||
* @param wrappedNode node with children
|
||||
* @param childLayerDepth number of subsequent generations.
|
||||
*/
|
||||
private TableFilterChildrenWithDescendants(Node wrappedNode, int childLayerDepth) {
|
||||
super(wrappedNode);
|
||||
this.childLayerDepth = childLayerDepth;
|
||||
}
|
||||
|
||||
public static Children createInstance(Node wrappedNode, boolean createChildren){
|
||||
if(createChildren){
|
||||
return new TableFilterChildrenWithDescendants(wrappedNode);
|
||||
} else {
|
||||
/**
|
||||
* Factory method for getting an instance of the Children object based on the
|
||||
* node with children, and the number of subsequent generations.
|
||||
*
|
||||
* @param wrappedNode node that has children
|
||||
* @param childLayerDepth
|
||||
* @return object capable of generating child node
|
||||
*/
|
||||
public static Children createInstance(Node wrappedNode, int childLayerDepth){
|
||||
if(childLayerDepth == 0){
|
||||
return Children.LEAF;
|
||||
} else {
|
||||
return new TableFilterChildrenWithDescendants(wrappedNode, childLayerDepth - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node copyNode(Node nodeToCopy){
|
||||
return new TableFilterNode(nodeToCopy, true, true);
|
||||
}
|
||||
return new TableFilterNode(nodeToCopy, this.childLayerDepth);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||
public class TableFilterNode extends FilterNode {
|
||||
|
||||
private final boolean createChildren;
|
||||
private boolean forceUseWrappedDisplayName = false;
|
||||
private final boolean forceUseWrappedDisplayName;
|
||||
private String columnOrderKey = "NONE";
|
||||
|
||||
/**
|
||||
@ -48,34 +48,8 @@ public class TableFilterNode extends FilterNode {
|
||||
*/
|
||||
public TableFilterNode(Node node, boolean createChildren) {
|
||||
super(node, TableFilterChildren.createInstance(node, createChildren), Lookups.proxy(node));
|
||||
this.createChildren = createChildren;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a filter node that generates children using
|
||||
* TableFilterChildrenWithDescendants. This enables row to have descendants.
|
||||
*
|
||||
* Enables use of <code>getDisplayName()</code> for children of this node.
|
||||
*
|
||||
* @param node The node to wrap
|
||||
*/
|
||||
public TableFilterNode(Node node) {
|
||||
super(node, TableFilterChildrenWithDescendants.createInstance(node, true), Lookups.proxy(node));
|
||||
this.createChildren = true;
|
||||
this.forceUseWrappedDisplayName = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be used in TableFilterChildrenWithDescendants.
|
||||
*
|
||||
* @param node node to wrap
|
||||
* @param createChildren node has children?
|
||||
* @param forceUseWrappedDisplayName allow use of custom <code>getDisplayName()</code> .
|
||||
*/
|
||||
TableFilterNode(Node node, boolean createChildren, boolean forceUseWrappedDisplayName) {
|
||||
super(node, TableFilterChildren.createInstance(node, createChildren), Lookups.proxy(node));
|
||||
this.createChildren = createChildren;
|
||||
this.forceUseWrappedDisplayName = forceUseWrappedDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,9 +66,16 @@ public class TableFilterNode extends FilterNode {
|
||||
*/
|
||||
public TableFilterNode(Node node, boolean createChildren, String columnOrderKey) {
|
||||
super(node, TableFilterChildren.createInstance(node, createChildren));
|
||||
this.forceUseWrappedDisplayName = false;
|
||||
this.createChildren = createChildren;
|
||||
this.columnOrderKey = columnOrderKey;
|
||||
}
|
||||
|
||||
public TableFilterNode(Node node, int childLayerDepth){
|
||||
super(node, TableFilterChildrenWithDescendants.createInstance(node, childLayerDepth), Lookups.proxy(node));
|
||||
this.createChildren = true;
|
||||
this.forceUseWrappedDisplayName = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display name for the wrapped node, for use in the first column
|
||||
@ -113,10 +94,6 @@ public class TableFilterNode extends FilterNode {
|
||||
}
|
||||
}
|
||||
|
||||
protected String getParentDisplayName() {
|
||||
return super.getDisplayName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds information about which child node of this node, if any, should be
|
||||
* selected. Can be null.
|
||||
@ -159,8 +136,7 @@ public class TableFilterNode extends FilterNode {
|
||||
* DataResultViewerTable. The key should represent what kinds of items the
|
||||
* table is showing.
|
||||
*/
|
||||
String getColumnOrderKey() {
|
||||
public String getColumnOrderKey() {
|
||||
return columnOrderKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -124,9 +124,9 @@ public class ImageUtils {
|
||||
if (OpenCvLoader.isOpenCvLoaded()) {
|
||||
try {
|
||||
if (System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64")) { //NON-NLS
|
||||
System.loadLibrary("opencv_ffmpeg2413_64"); //NON-NLS
|
||||
System.loadLibrary("opencv_ffmpeg248_64"); //NON-NLS
|
||||
} else {
|
||||
System.loadLibrary("opencv_ffmpeg2413"); //NON-NLS
|
||||
System.loadLibrary("opencv_ffmpeg248"); //NON-NLS
|
||||
}
|
||||
tempFfmpegLoaded = true;
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
|
@ -19,6 +19,9 @@
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesNode;
|
||||
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceNode;
|
||||
import org.sleuthkit.autopsy.commonfilesearch.InstanceCountNode;
|
||||
import org.sleuthkit.autopsy.commonfilesearch.Md5Node;
|
||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
|
||||
@ -119,6 +122,8 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
T visit(FileInstanceNode fin);
|
||||
|
||||
T visit(CommonFileChildNodeLoading cfcnl);
|
||||
|
||||
T visit(InstanceCountNode icn);
|
||||
|
||||
/*
|
||||
* Tags
|
||||
@ -202,6 +207,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
public T visit(CommonFilesNode cfn) {
|
||||
return defaultVisit(cfn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(InstanceCountNode icn){
|
||||
return defaultVisit(icn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(CommonFileChildNodeLoading cfcnl) {
|
||||
|
@ -1,127 +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.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
* Used by the Common Files search feature to encapsulate instances of a given
|
||||
* MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
|
||||
*/
|
||||
public class FileInstanceNode extends FileNode {
|
||||
|
||||
private final String dataSource;
|
||||
|
||||
public FileInstanceNode(AbstractFile fsContent, String dataSource) {
|
||||
super(fsContent);
|
||||
this.content = fsContent;
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractFile getContent() {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
String getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
@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<>();
|
||||
fillPropertyMap(map, this);
|
||||
|
||||
final String NO_DESCR = Bundle.AbstractFsContentNode_noDesc_text();
|
||||
for (CommonFilePropertyType propType : CommonFilePropertyType.values()) {
|
||||
final String propString = propType.toString();
|
||||
final Object property = map.get(propString);
|
||||
final NodeProperty<Object> nodeProperty = new NodeProperty<>(propString, propString, NO_DESCR, property);
|
||||
sheetSet.put(nodeProperty);
|
||||
}
|
||||
|
||||
this.addTagProperty(sheetSet);
|
||||
|
||||
return sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill map with AbstractFile properties
|
||||
*
|
||||
* @param map map with preserved ordering, where property names/values are
|
||||
* put
|
||||
* @param node The item to get properties for.
|
||||
*/
|
||||
static private void fillPropertyMap(Map<String, Object> map, FileInstanceNode node) {
|
||||
|
||||
map.put(CommonFilePropertyType.File.toString(), node.getName());
|
||||
map.put(CommonFilePropertyType.ParentPath.toString(), node.getContent().getParentPath());
|
||||
map.put(CommonFilePropertyType.HashsetHits.toString(), getHashSetHitsForFile(node.getContent()));
|
||||
map.put(CommonFilePropertyType.DataSource.toString(), node.getDataSource());
|
||||
map.put(CommonFilePropertyType.MimeType.toString(), StringUtils.defaultString(node.content.getMIMEType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the columns to be displayed for reach row represented by an
|
||||
* instance of this object.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"CommonFilePropertyType.fileColLbl=File",
|
||||
"CommonFilePropertyType.pathColLbl=Parent Path",
|
||||
"CommonFilePropertyType.hashsetHitsColLbl=Hash Set Hits",
|
||||
"CommonFilePropertyType.dataSourceColLbl=Data Source",
|
||||
"CommonFilePropertyType.mimeTypeColLbl=MIME Type"
|
||||
})
|
||||
public enum CommonFilePropertyType {
|
||||
|
||||
File(Bundle.CommonFilePropertyType_fileColLbl()),
|
||||
ParentPath(Bundle.CommonFilePropertyType_pathColLbl()),
|
||||
HashsetHits(Bundle.CommonFilePropertyType_hashsetHitsColLbl()),
|
||||
DataSource(Bundle.CommonFilePropertyType_dataSourceColLbl()),
|
||||
MimeType(Bundle.CommonFilePropertyType_mimeTypeColLbl());
|
||||
|
||||
final private String displayString;
|
||||
|
||||
private CommonFilePropertyType(String displayString) {
|
||||
this.displayString = displayString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayString;
|
||||
}
|
||||
}
|
||||
}
|
@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction;
|
||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceNode;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -54,6 +55,8 @@ import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode;
|
||||
import org.sleuthkit.autopsy.commonfilesearch.InstanceCountNode;
|
||||
import org.sleuthkit.autopsy.commonfilesearch.Md5Node;
|
||||
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode;
|
||||
@ -526,6 +529,21 @@ public class DataResultFilterNode extends FilterNode {
|
||||
*/
|
||||
private class GetPreferredActionsDisplayableItemNodeVisitor extends DisplayableItemNodeVisitor.Default<AbstractAction> {
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(InstanceCountNode icn){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(Md5Node md5n){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(FileInstanceNode fin){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(BlackboardArtifactNode ban) {
|
||||
BlackboardArtifact artifact = ban.getArtifact();
|
||||
|
@ -18,11 +18,10 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="treeView" alignment="0" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="backButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="backButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="forwardButton" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="65" max="32767" attributes="0"/>
|
||||
<Component id="forwardButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="51" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
@ -43,14 +42,14 @@
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="forwardButton" min="-2" pref="26" max="-2" attributes="1"/>
|
||||
<Component id="backButton" min="-2" pref="26" max="-2" attributes="1"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="forwardButton" max="32767" attributes="1"/>
|
||||
<Component id="backButton" min="-2" max="-2" attributes="1"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="treeView" pref="838" max="32767" attributes="0"/>
|
||||
<Component id="treeView" pref="843" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
@ -72,7 +71,7 @@
|
||||
<Component class="javax.swing.JButton" name="backButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_large.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.backButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
@ -80,7 +79,7 @@
|
||||
<Property name="borderPainted" type="boolean" value="false"/>
|
||||
<Property name="contentAreaFilled" type="boolean" value="false"/>
|
||||
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled_large.png"/>
|
||||
</Property>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 0, 2, 0]"/>
|
||||
@ -92,10 +91,10 @@
|
||||
<Dimension value="[5, 5]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[23, 23]"/>
|
||||
<Dimension value="[32, 32]"/>
|
||||
</Property>
|
||||
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_back_hover_large.png"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
@ -105,7 +104,7 @@
|
||||
<Component class="javax.swing.JButton" name="forwardButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_large.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="DirectoryTreeTopComponent.forwardButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
@ -113,7 +112,7 @@
|
||||
<Property name="borderPainted" type="boolean" value="false"/>
|
||||
<Property name="contentAreaFilled" type="boolean" value="false"/>
|
||||
<Property name="disabledIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled_large.png"/>
|
||||
</Property>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[2, 0, 2, 0]"/>
|
||||
@ -125,10 +124,10 @@
|
||||
<Dimension value="[5, 5]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[23, 23]"/>
|
||||
<Dimension value="[32, 32]"/>
|
||||
</Property>
|
||||
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"/>
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover_large.png"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
|
@ -184,32 +184,32 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
|
||||
treeView.setBorder(null);
|
||||
|
||||
backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back.png"))); // NOI18N
|
||||
backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_large.png"))); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N
|
||||
backButton.setBorderPainted(false);
|
||||
backButton.setContentAreaFilled(false);
|
||||
backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled.png"))); // NOI18N
|
||||
backButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_disabled_large.png"))); // NOI18N
|
||||
backButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
|
||||
backButton.setMaximumSize(new java.awt.Dimension(55, 100));
|
||||
backButton.setMinimumSize(new java.awt.Dimension(5, 5));
|
||||
backButton.setPreferredSize(new java.awt.Dimension(23, 23));
|
||||
backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"))); // NOI18N
|
||||
backButton.setPreferredSize(new java.awt.Dimension(32, 32));
|
||||
backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover_large.png"))); // NOI18N
|
||||
backButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
backButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward.png"))); // NOI18N
|
||||
forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_large.png"))); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(forwardButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.forwardButton.text")); // NOI18N
|
||||
forwardButton.setBorderPainted(false);
|
||||
forwardButton.setContentAreaFilled(false);
|
||||
forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled.png"))); // NOI18N
|
||||
forwardButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_disabled_large.png"))); // NOI18N
|
||||
forwardButton.setMargin(new java.awt.Insets(2, 0, 2, 0));
|
||||
forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
|
||||
forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
|
||||
forwardButton.setPreferredSize(new java.awt.Dimension(23, 23));
|
||||
forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"))); // NOI18N
|
||||
forwardButton.setPreferredSize(new java.awt.Dimension(32, 32));
|
||||
forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover_large.png"))); // NOI18N
|
||||
forwardButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
forwardButtonActionPerformed(evt);
|
||||
@ -231,11 +231,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(treeView)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 65, Short.MAX_VALUE)
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 51, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(showRejectedCheckBox)
|
||||
.addComponent(groupByDatasourceCheckBox))
|
||||
@ -252,11 +251,11 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
.addComponent(groupByDatasourceCheckBox))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(forwardButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 838, Short.MAX_VALUE)
|
||||
.addComponent(treeView, javax.swing.GroupLayout.DEFAULT_SIZE, 843, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
@ -800,10 +799,23 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds the directory tree
|
||||
* Rebuilds the autopsy tree.
|
||||
*
|
||||
* Does nothing if there is no open case.
|
||||
*/
|
||||
private void rebuildTree() {
|
||||
|
||||
// if no open case or has no data then there is no tree to rebuild
|
||||
Case currentCase;
|
||||
try {
|
||||
currentCase = Case.getCurrentCaseThrows();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
return;
|
||||
}
|
||||
if (null == currentCase || currentCase.hasData() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// refresh all children of the root.
|
||||
autopsyTreeChildrenFactory.refreshChildren();
|
||||
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
@ -35,6 +35,7 @@ import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import org.openide.DialogDisplayer;
|
||||
import org.openide.NotifyDescriptor;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.TopComponent;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
@ -43,6 +44,7 @@ import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.datamodel.EmptyNode;
|
||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
@ -166,6 +168,7 @@ class FileSearchPanel extends javax.swing.JPanel {
|
||||
* Action when the "Search" button is pressed.
|
||||
*
|
||||
*/
|
||||
@NbBundle.Messages("FileSearchPanel.emptyNode.display.text=No results found.")
|
||||
private void search() {
|
||||
// change the cursor to "waiting cursor" for this operation
|
||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
@ -192,9 +195,16 @@ class FileSearchPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
SearchNode sn = new SearchNode(contentList);
|
||||
final TopComponent searchResultWin = DataResultTopComponent.createInstance(title, pathText,
|
||||
new TableFilterNode(sn, true, sn.getName()), contentList.size());
|
||||
|
||||
TableFilterNode tableFilterNode = new TableFilterNode(sn, true, sn.getName());
|
||||
final TopComponent searchResultWin;
|
||||
if (contentList.isEmpty()) {
|
||||
Node emptyNode = new EmptyNode(Bundle.FileSearchPanel_emptyNode_display_text());
|
||||
searchResultWin = DataResultTopComponent.createInstance(title, pathText,
|
||||
emptyNode, 0);
|
||||
} else {
|
||||
searchResultWin = DataResultTopComponent.createInstance(title, pathText,
|
||||
tableFilterNode, contentList.size());
|
||||
}
|
||||
searchResultWin.requestActive(); // make it the active top component
|
||||
|
||||
/**
|
||||
|
@ -61,8 +61,8 @@ public class HealthMonitorDashboard {
|
||||
private final static String ADMIN_ACCESS_FILE_NAME = "adminAccess"; // NON-NLS
|
||||
private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(Places.getUserDirectory().getAbsolutePath(), ADMIN_ACCESS_FILE_NAME).toString();
|
||||
|
||||
Map<String, List<EnterpriseHealthMonitor.DatabaseTimingResult>> timingData;
|
||||
List<EnterpriseHealthMonitor.UserData> userData;
|
||||
Map<String, List<HealthMonitor.DatabaseTimingResult>> timingData;
|
||||
List<HealthMonitor.UserData> userData;
|
||||
|
||||
private JComboBox<String> timingDateComboBox = null;
|
||||
private JComboBox<String> timingHostComboBox = null;
|
||||
@ -90,7 +90,7 @@ public class HealthMonitorDashboard {
|
||||
* Display the dashboard.
|
||||
*/
|
||||
@NbBundle.Messages({"HealthMonitorDashboard.display.errorCreatingDashboard=Error creating health monitor dashboard",
|
||||
"HealthMonitorDashboard.display.dashboardTitle=Enterprise Health Monitor"})
|
||||
"HealthMonitorDashboard.display.dashboardTitle=Health Monitor"})
|
||||
public void display() {
|
||||
|
||||
// Update the enabled status and get the timing data, then create all
|
||||
@ -153,14 +153,14 @@ public class HealthMonitorDashboard {
|
||||
private void updateData() throws HealthMonitorException {
|
||||
|
||||
// Update the monitor status
|
||||
EnterpriseHealthMonitor.getInstance().updateFromGlobalEnabledStatus();
|
||||
HealthMonitor.getInstance().updateFromGlobalEnabledStatus();
|
||||
|
||||
if(EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(HealthMonitor.monitorIsEnabled()) {
|
||||
// Get a copy of the timing data from the database
|
||||
timingData = EnterpriseHealthMonitor.getInstance().getTimingMetricsFromDatabase(DateRange.getMaximumTimestampRange());
|
||||
timingData = HealthMonitor.getInstance().getTimingMetricsFromDatabase(DateRange.getMaximumTimestampRange());
|
||||
|
||||
// Get a copy of the user data from the database
|
||||
userData = EnterpriseHealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.getMaximumTimestampRange());
|
||||
userData = HealthMonitor.getInstance().getUserMetricsFromDatabase(DateRange.getMaximumTimestampRange());
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ public class HealthMonitorDashboard {
|
||||
private JPanel createTimingPanel() throws HealthMonitorException {
|
||||
|
||||
// If the monitor isn't enabled, just add a message
|
||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(! HealthMonitor.monitorIsEnabled()) {
|
||||
//timingMetricPanel.setPreferredSize(new Dimension(400,100));
|
||||
JPanel emptyTimingMetricPanel = new JPanel();
|
||||
emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle()));
|
||||
@ -223,7 +223,7 @@ public class HealthMonitorDashboard {
|
||||
JPanel timingControlPanel = new JPanel();
|
||||
|
||||
// If the monitor is not enabled, don't add any components
|
||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(! HealthMonitor.monitorIsEnabled()) {
|
||||
return timingControlPanel;
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ public class HealthMonitorDashboard {
|
||||
// Create an array of host names
|
||||
Set<String> hostNameSet = new HashSet<>();
|
||||
for(String metricType:timingData.keySet()) {
|
||||
for(EnterpriseHealthMonitor.DatabaseTimingResult result: timingData.get(metricType)) {
|
||||
for(HealthMonitor.DatabaseTimingResult result: timingData.get(metricType)) {
|
||||
hostNameSet.add(result.getHostName());
|
||||
}
|
||||
}
|
||||
@ -364,7 +364,7 @@ public class HealthMonitorDashboard {
|
||||
for(String metricName:timingData.keySet()) {
|
||||
|
||||
// If necessary, trim down the list of results to fit the selected time range
|
||||
List<EnterpriseHealthMonitor.DatabaseTimingResult> intermediateTimingDataForDisplay;
|
||||
List<HealthMonitor.DatabaseTimingResult> intermediateTimingDataForDisplay;
|
||||
if(timingDateComboBox.getSelectedItem() != null) {
|
||||
DateRange selectedDateRange = DateRange.fromLabel(timingDateComboBox.getSelectedItem().toString());
|
||||
long threshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
|
||||
@ -403,7 +403,7 @@ public class HealthMonitorDashboard {
|
||||
"HealthMonitorDashboard.createUserPanel.userMetricsTitle=User Metrics"})
|
||||
private JPanel createUserPanel() throws HealthMonitorException {
|
||||
// If the monitor isn't enabled, just add a message
|
||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(! HealthMonitor.monitorIsEnabled()) {
|
||||
JPanel emptyUserMetricPanel = new JPanel();
|
||||
emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle()));
|
||||
emptyUserMetricPanel.add(new JLabel(" "));
|
||||
@ -448,7 +448,7 @@ public class HealthMonitorDashboard {
|
||||
JPanel userControlPanel = new JPanel();
|
||||
|
||||
// If the monitor is not enabled, don't add any components
|
||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
||||
if(! HealthMonitor.monitorIsEnabled()) {
|
||||
return userControlPanel;
|
||||
}
|
||||
|
||||
@ -535,7 +535,7 @@ public class HealthMonitorDashboard {
|
||||
JButton enableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_enableButton());
|
||||
JButton disableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_disableButton());
|
||||
|
||||
boolean isEnabled = EnterpriseHealthMonitor.monitorIsEnabled();
|
||||
boolean isEnabled = HealthMonitor.monitorIsEnabled();
|
||||
enableButton.setEnabled(! isEnabled);
|
||||
disableButton.setEnabled(isEnabled);
|
||||
|
||||
@ -545,7 +545,7 @@ public class HealthMonitorDashboard {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
try {
|
||||
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
EnterpriseHealthMonitor.setEnabled(true);
|
||||
HealthMonitor.setEnabled(true);
|
||||
redisplay();
|
||||
} catch (HealthMonitorException ex) {
|
||||
logger.log(Level.SEVERE, "Error enabling monitoring", ex);
|
||||
@ -561,7 +561,7 @@ public class HealthMonitorDashboard {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
try {
|
||||
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
EnterpriseHealthMonitor.setEnabled(false);
|
||||
HealthMonitor.setEnabled(false);
|
||||
redisplay();
|
||||
} catch (HealthMonitorException ex) {
|
||||
logger.log(Level.SEVERE, "Error disabling monitoring", ex);
|
||||
|
@ -45,7 +45,7 @@ public class Installer extends ModuleInstall {
|
||||
public void restored() {
|
||||
|
||||
try {
|
||||
EnterpriseHealthMonitor.startUpIfEnabled();
|
||||
HealthMonitor.startUpIfEnabled();
|
||||
} catch (HealthMonitorException ex) {
|
||||
logger.log(Level.SEVERE, "Error starting health services monitor", ex);
|
||||
}
|
||||
@ -54,7 +54,7 @@ public class Installer extends ModuleInstall {
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
EnterpriseHealthMonitor.shutdown();
|
||||
HealthMonitor.shutdown();
|
||||
} catch (HealthMonitorException ex) {
|
||||
logger.log(Level.SEVERE, "Error stopping health services monitor", ex);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ import java.util.logging.Level;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor.DatabaseTimingResult;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor.DatabaseTimingResult;
|
||||
|
||||
/**
|
||||
* Creates a graph of the given timing metric data
|
||||
|
@ -38,7 +38,7 @@ import javax.swing.JPanel;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor.UserData;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor.UserData;
|
||||
|
||||
/**
|
||||
* Creates graphs using the given user metric data
|
||||
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2014 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.ingest;
|
||||
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* Provides a mechanism for creating and persisting an ingest job configuration
|
||||
* for a particular context and for launching ingest jobs that process one or
|
||||
* more data sources using the ingest job configuration.
|
||||
*
|
||||
* @deprecated Use the IngestModuleSettings and IngestJobConfigurationPanel
|
||||
* classes and IngestManager.beginIngestJob() instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class IngestJobConfigurator {
|
||||
|
||||
private final IngestJobSettings settings;
|
||||
private final IngestJobSettingsPanel settingsPanel;
|
||||
|
||||
/**
|
||||
* Constructs an ingest job launcher that creates and persists ingest job
|
||||
* settings for a particular context and launches ingest jobs that process
|
||||
* one or more data sources using the settings.
|
||||
*
|
||||
* @param context The context identifier.
|
||||
*/
|
||||
@Deprecated
|
||||
public IngestJobConfigurator(String context) {
|
||||
this.settings = new IngestJobSettings(context);
|
||||
this.settingsPanel = new IngestJobSettingsPanel(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets any warnings generated when the persisted ingest job settings for
|
||||
* the specified context are loaded or saved.
|
||||
*
|
||||
* @return A collection of warning messages, possibly empty.
|
||||
*/
|
||||
@Deprecated
|
||||
public List<String> getIngestJobConfigWarnings() {
|
||||
return this.settings.getWarnings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user interface panel the launcher uses to obtain the user's
|
||||
* ingest job settings for the specified context.
|
||||
*
|
||||
* @return The panel.
|
||||
*/
|
||||
@Deprecated
|
||||
public JPanel getIngestJobConfigPanel() {
|
||||
return settingsPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the ingest job settings for the specified context.
|
||||
*/
|
||||
@Deprecated
|
||||
public void saveIngestJobConfig() {
|
||||
this.settings.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches ingest job for one or more data sources using the ingest job
|
||||
* settings for the specified context.
|
||||
*
|
||||
* @param dataSources The data sources to ingest.
|
||||
*/
|
||||
@Deprecated
|
||||
public void startIngestJobs(List<Content> dataSources) {
|
||||
IngestManager.getInstance().queueIngestJob(dataSources, this.settings);
|
||||
}
|
||||
}
|
@ -95,7 +95,7 @@ public class FileTypeDetector {
|
||||
private static SortedSet<String> getTikaDetectedTypes() {
|
||||
if (null == tikaDetectedTypes) {
|
||||
tikaDetectedTypes = org.apache.tika.mime.MimeTypes.getDefaultMimeTypes().getMediaTypeRegistry().getTypes()
|
||||
.stream().filter(t -> !t.hasParameters()).map(s -> s.toString()).collect(Collectors.toCollection(TreeSet::new));
|
||||
.stream().filter(t -> !t.hasParameters()).map(s -> s.toString().replace("tika-", "")).collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
return Collections.unmodifiableSortedSet(tikaDetectedTypes);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
import org.sleuthkit.autopsy.ingest.FileIngestModule;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||
@ -184,7 +184,7 @@ public class HashDbIngestModule implements FileIngestModule {
|
||||
String md5Hash = file.getMd5Hash();
|
||||
if (md5Hash == null || md5Hash.isEmpty()) {
|
||||
try {
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Disk Reads: Hash calculation");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Disk Reads: Hash calculation");
|
||||
long calcstart = System.currentTimeMillis();
|
||||
md5Hash = HashUtility.calculateMd5Hash(file);
|
||||
if (file.getSize() > 0) {
|
||||
@ -192,10 +192,10 @@ public class HashDbIngestModule implements FileIngestModule {
|
||||
// strongly with file size until the files get large.
|
||||
// Only normalize if the file size is greater than ~1MB.
|
||||
if (file.getSize() < 1000000) {
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
} else {
|
||||
// In testing, this normalization gave reasonable resuls
|
||||
EnterpriseHealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000);
|
||||
HealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000);
|
||||
}
|
||||
}
|
||||
file.setMd5Hash(md5Hash);
|
||||
|
@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.MetaTypeCond
|
||||
*/
|
||||
public final class FilesSetsManager extends Observable {
|
||||
|
||||
@NbBundle.Messages({"FilesSetsManager.allFilesAndDirectories=All Files and Directories",
|
||||
@NbBundle.Messages({"FilesSetsManager.allFilesAndDirectories=All Files and Directories (Not Unallocated Space)",
|
||||
"FilesSetsManager.allFilesDirectoriesAndUnallocated=All Files, Directories, and Unallocated Space"})
|
||||
private static final List<String> ILLEGAL_FILE_NAME_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", "/", ":", "*", "?", "\"", "<", ">")));
|
||||
private static final List<String> ILLEGAL_FILE_PATH_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", ":", "*", "?", "\"", "<", ">")));
|
||||
|
@ -69,7 +69,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* - file.dat (empty file)
|
||||
*/
|
||||
class IntraCaseUtils {
|
||||
|
||||
|
||||
private static final String CASE_NAME = "IntraCaseCommonFilesSearchTest";
|
||||
static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), CASE_NAME);
|
||||
|
||||
@ -77,35 +77,35 @@ class IntraCaseUtils {
|
||||
private final Path imagePath2;
|
||||
private final Path imagePath3;
|
||||
private final Path imagePath4;
|
||||
|
||||
|
||||
static final String IMG = "IMG_6175.jpg";
|
||||
static final String DOC = "BasicStyleGuide.doc";
|
||||
static final String PDF = "adsf.pdf"; //not a typo - it appears this way in the test image
|
||||
static final String EMPTY = "file.dat";
|
||||
|
||||
|
||||
static final String SET1 = "CommonFiles_img1_v1.vhd";
|
||||
static final String SET2 = "CommonFiles_img2_v1.vhd";
|
||||
static final String SET3 = "CommonFiles_img3_v1.vhd";
|
||||
static final String SET4 = "CommonFiles_img4_v1.vhd";
|
||||
|
||||
|
||||
private final DataSourceLoader dataSourceLoader;
|
||||
|
||||
|
||||
private final String caseName;
|
||||
|
||||
IntraCaseUtils(NbTestCase nbTestCase, String caseName){
|
||||
|
||||
IntraCaseUtils(NbTestCase nbTestCase, String caseName) {
|
||||
imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), SET1);
|
||||
imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), SET2);
|
||||
imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), SET3);
|
||||
imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), SET4);
|
||||
|
||||
|
||||
this.dataSourceLoader = new DataSourceLoader();
|
||||
|
||||
|
||||
this.caseName = caseName;
|
||||
}
|
||||
|
||||
void setUp(){
|
||||
|
||||
void setUp() {
|
||||
CaseUtils.createAsCurrentCase(this.caseName);
|
||||
|
||||
|
||||
final ImageDSProcessor imageDSProcessor = new ImageDSProcessor();
|
||||
|
||||
IngestUtils.addDataSource(imageDSProcessor, imagePath1);
|
||||
@ -113,12 +113,12 @@ class IntraCaseUtils {
|
||||
IngestUtils.addDataSource(imageDSProcessor, imagePath3);
|
||||
IngestUtils.addDataSource(imageDSProcessor, imagePath4);
|
||||
}
|
||||
|
||||
Map<Long, String> getDataSourceMap() throws NoCurrentCaseException, TskCoreException, SQLException{
|
||||
|
||||
Map<Long, String> getDataSourceMap() throws NoCurrentCaseException, TskCoreException, SQLException {
|
||||
return this.dataSourceLoader.getDataSourceMap();
|
||||
}
|
||||
|
||||
void tearDown(){
|
||||
|
||||
void tearDown() {
|
||||
CaseUtils.closeCurrentCase(false);
|
||||
try {
|
||||
CaseUtils.deleteCaseDir(CASE_DIRECTORY_PATH.toFile());
|
||||
@ -127,18 +127,18 @@ class IntraCaseUtils {
|
||||
//does not represent a failure in the common files search feature
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the given file appears a precise number times in the given
|
||||
* Verify that the given file appears a precise number times in the given
|
||||
* data source.
|
||||
*
|
||||
*
|
||||
* @param files search domain
|
||||
* @param objectIdToDataSource mapping of file ids to data source names
|
||||
* @param name name of file to search for
|
||||
* @param dataSource name of data source where file should appear
|
||||
* @param count number of appearances of the given file
|
||||
* @return true if a file with the given name exists the specified number
|
||||
* of times in the given data source
|
||||
* @return true if a file with the given name exists the specified number of
|
||||
* times in the given data source
|
||||
*/
|
||||
static boolean verifyFileExistanceAndCount(List<AbstractFile> files, Map<Long, String> objectIdToDataSource, String name, String dataSource, int count) {
|
||||
|
||||
@ -161,26 +161,28 @@ class IntraCaseUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method which verifies that a file exists within a given data
|
||||
* Convenience method which verifies that a file exists within a given data
|
||||
* source exactly once.
|
||||
*
|
||||
*
|
||||
* @param files search domain
|
||||
* @param objectIdToDataSource mapping of file ids to data source names
|
||||
* @param name name of file to search for
|
||||
* @param dataSource name of data source where file should appear
|
||||
* @return true if a file with the given name exists once in the given data
|
||||
* source
|
||||
* @return true if a file with the given name exists once in the given data
|
||||
* source
|
||||
*/
|
||||
static boolean verifySingularFileExistance(List<AbstractFile> files, Map<Long, String> objectIdToDataSource, String name, String dataSource) {
|
||||
return verifyFileExistanceAndCount(files, objectIdToDataSource, name, dataSource, 1);
|
||||
}
|
||||
|
||||
|
||||
static Map<Long, String> mapFileInstancesToDataSources(CommonFilesMetadata metadata) {
|
||||
Map<Long, String> instanceIdToDataSource = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, Md5Metadata> entry : metadata.getMetadata().entrySet()) {
|
||||
for (FileInstanceMetadata md : entry.getValue().getMetadata()) {
|
||||
instanceIdToDataSource.put(md.getObjectId(), md.getDataSourceName());
|
||||
for (Map.Entry<Integer, List<Md5Metadata>> entry : metadata.getMetadata().entrySet()) {
|
||||
for (Md5Metadata md : entry.getValue()) {
|
||||
for (FileInstanceMetadata fim : md.getMetadata()) {
|
||||
instanceIdToDataSource.put(fim.getObjectId(), fim.getDataSourceName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,18 +204,18 @@ class IntraCaseUtils {
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
static Long getDataSourceIdByName(String name, Map<Long, String> dataSources){
|
||||
|
||||
if(dataSources.containsValue(name)){
|
||||
for(Map.Entry<Long, String> dataSource : dataSources.entrySet()){
|
||||
if(dataSource.getValue().equals(name)){
|
||||
|
||||
static Long getDataSourceIdByName(String name, Map<Long, String> dataSources) {
|
||||
|
||||
if (dataSources.containsValue(name)) {
|
||||
for (Map.Entry<Long, String> dataSource : dataSources.entrySet()) {
|
||||
if (dataSource.getValue().equals(name)) {
|
||||
return dataSource.getKey();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IndexOutOfBoundsException(String.format("Name should be one of: {0}", String.join(",", dataSources.values())));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ file.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10
|
||||
file.reference.log4j-1.2.17.jar=release/modules/ext/log4j-1.2.17.jar
|
||||
file.reference.logkit-1.0.1.jar=release/modules/ext/logkit-1.0.1.jar
|
||||
file.reference.mail-1.4.3.jar=release/modules/ext/mail-1.4.3.jar
|
||||
file.reference.opencv-2413.jar=release/modules/ext/opencv-2413.jar
|
||||
file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar
|
||||
file.reference.openjfx-dialogs-1.0.2.jar=release/modules/ext/openjfx-dialogs-1.0.3.jar
|
||||
file.reference.platform-3.4.0.jar=release/modules/ext/platform-3.4.0.jar
|
||||
file.reference.poi-3.17.jar=release/modules/ext/poi-3.17.jar
|
||||
|
@ -746,8 +746,8 @@
|
||||
<binary-origin>release/modules/ext/jfxtras-common-8.0-r4.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/opencv-2413.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/opencv-2413.jar</binary-origin>
|
||||
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jsr305-1.3.9.jar</runtime-relative-path>
|
||||
|
@ -483,7 +483,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
|
||||
private void handleRemoteNodeControlEvent(AutoIngestNodeControlEvent event) {
|
||||
if (event.getTargetNodeName().compareToIgnoreCase(LOCAL_HOST_NAME) == 0) {
|
||||
sysLogger.log(Level.INFO, "Received {0} event from user {1} on machine {2}", new Object[]{event.getControlEventType().toString(), event.getUserName(), event.getOriginatingNodeName()});
|
||||
sysLogger.log(Level.INFO, "Received {0} event from user {1} on machine {2}", new Object[] {event.getControlEventType().toString(), event.getUserName(), event.getOriginatingNodeName()});
|
||||
switch (event.getControlEventType()) {
|
||||
case PAUSE:
|
||||
pause();
|
||||
@ -2072,14 +2072,21 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
* while reading the lock data
|
||||
*/
|
||||
private Lock dequeueAndLockNextJob() throws CoordinationServiceException, InterruptedException {
|
||||
sysLogger.log(Level.INFO, "Checking pending jobs queue for ready job");
|
||||
sysLogger.log(Level.INFO, "Checking pending jobs queue for ready job, enforcing max jobs per case");
|
||||
Lock manifestLock;
|
||||
synchronized (jobsLock) {
|
||||
manifestLock = dequeueAndLockNextJobHelper();
|
||||
manifestLock = dequeueAndLockNextJob(true);
|
||||
if (null != manifestLock) {
|
||||
sysLogger.log(Level.INFO, "Dequeued job for {0}", currentJob.getManifest().getFilePath());
|
||||
} else {
|
||||
sysLogger.log(Level.INFO, "No ready job");
|
||||
sysLogger.log(Level.INFO, "Checking pending jobs queue for ready job, not enforcing max jobs per case");
|
||||
manifestLock = dequeueAndLockNextJob(false);
|
||||
if (null != manifestLock) {
|
||||
sysLogger.log(Level.INFO, "Dequeued job for {0}", currentJob.getManifest().getFilePath());
|
||||
} else {
|
||||
sysLogger.log(Level.INFO, "No ready job");
|
||||
}
|
||||
}
|
||||
}
|
||||
return manifestLock;
|
||||
@ -2091,6 +2098,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
* queue, made the current job, and a coordination service lock on the
|
||||
* manifest for the job is returned.
|
||||
*
|
||||
* @param enforceMaxJobsPerCase Whether or not to enforce the maximum
|
||||
* concurrent jobs per case setting.
|
||||
*
|
||||
* @return A manifest file lock if a ready job was found, null
|
||||
* otherwise.
|
||||
@ -2101,7 +2110,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
* @throws InterruptedException if the thread is interrupted
|
||||
* while reading the lock data
|
||||
*/
|
||||
private Lock dequeueAndLockNextJobHelper() throws CoordinationServiceException, InterruptedException {
|
||||
private Lock dequeueAndLockNextJob(boolean enforceMaxJobsPerCase) throws CoordinationServiceException, InterruptedException {
|
||||
Lock manifestLock = null;
|
||||
synchronized (jobsLock) {
|
||||
Iterator<AutoIngestJob> iterator = pendingJobs.iterator();
|
||||
@ -2131,6 +2140,19 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
continue;
|
||||
}
|
||||
|
||||
if (enforceMaxJobsPerCase) {
|
||||
int currentJobsForCase = 0;
|
||||
for (AutoIngestJob runningJob : hostNamesToRunningJobs.values()) {
|
||||
if (0 == job.getManifest().getCaseName().compareTo(runningJob.getManifest().getCaseName())) {
|
||||
++currentJobsForCase;
|
||||
}
|
||||
}
|
||||
if (currentJobsForCase >= AutoIngestUserPreferences.getMaxConcurrentJobsForOneCase()) {
|
||||
manifestLock.release();
|
||||
manifestLock = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
iterator.remove();
|
||||
currentJob = job;
|
||||
break;
|
||||
@ -2434,7 +2456,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
throw new CaseManagementException(String.format("Error creating solr settings file for case %s for %s", caseName, manifest.getFilePath()), ex);
|
||||
} catch (CaseActionException ex) {
|
||||
throw new CaseManagementException(String.format("Error creating or opening case %s for %s", caseName, manifest.getFilePath()), ex);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new CaseManagementException(String.format("Timed out acquiring case name lock for %s for %s", caseName, manifest.getFilePath()));
|
||||
}
|
||||
|
@ -380,6 +380,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
throw new AutoIngestMonitorException("Error removing priority for job " + job.toString(), ex);
|
||||
}
|
||||
job.setPriority(DEFAULT_PRIORITY);
|
||||
|
||||
/**
|
||||
* Update job object in pending jobs queue
|
||||
*/
|
||||
jobsSnapshot.addOrReplacePendingJob(job);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -428,6 +433,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
throw new AutoIngestMonitorException("Error bumping priority for job " + job.toString(), ex);
|
||||
}
|
||||
job.setPriority(highestPriority);
|
||||
|
||||
/**
|
||||
* Update job object in pending jobs queue
|
||||
*/
|
||||
jobsSnapshot.addOrReplacePendingJob(job);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -466,7 +476,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
}
|
||||
|
||||
/*
|
||||
* If the job was still in the pending jobs queue, bump its
|
||||
* If the job was still in the pending jobs queue, reset its
|
||||
* priority.
|
||||
*/
|
||||
if (null != jobToDeprioritize) {
|
||||
@ -480,6 +490,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
}
|
||||
jobToDeprioritize.setPriority(DEFAULT_PRIORITY);
|
||||
|
||||
/**
|
||||
* Update job object in pending jobs queue
|
||||
*/
|
||||
jobsSnapshot.addOrReplacePendingJob(jobToDeprioritize);
|
||||
|
||||
/*
|
||||
* Publish a deprioritization event.
|
||||
*/
|
||||
@ -538,6 +553,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
}
|
||||
jobToPrioritize.setPriority(highestPriority);
|
||||
|
||||
/**
|
||||
* Update job object in pending jobs queue
|
||||
*/
|
||||
jobsSnapshot.addOrReplacePendingJob(jobToPrioritize);
|
||||
|
||||
/*
|
||||
* Publish a prioritization event.
|
||||
*/
|
||||
|
@ -37,8 +37,8 @@
|
||||
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
|
||||
<Component id="spMainScrollPane" min="-2" pref="106" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jPanelAutoIngestJobSettings" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="jPanelAutoIngestJobSettings" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -82,95 +82,103 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="cbTimeoutEnabled" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="lbNumberOfThreads" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="numberOfFileIngestThreadsComboBox" min="-2" pref="91" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="lbRestartRequired" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="1" max="-2" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="lbInputScanInterval" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="49" pref="49" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="lbRetriesAllowed" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="54" pref="54" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="lbConcurrentJobsPerCase" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbNumberOfThreads" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="1" max="-2" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="lbInputScanInterval" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="49" pref="49" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="lbRetriesAllowed" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="54" pref="54" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="21" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="41" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="spInputScanInterval" min="-2" pref="90" max="-2" attributes="0"/>
|
||||
<Component id="spMaximumRetryAttempts" min="-2" pref="90" max="-2" attributes="0"/>
|
||||
<Component id="spConcurrentJobsPerCase" alignment="1" min="-2" pref="90" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="lbSecondsBetweenJobs" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="spSecondsBetweenJobs" min="-2" pref="90" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="lbTimeoutText" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="spTimeoutHours" min="-2" pref="90" max="-2" attributes="0"/>
|
||||
<Component id="numberOfFileIngestThreadsComboBox" min="-2" pref="91" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lbSecondsBetweenJobsSeconds" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbTimeoutHours" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbInputScanIntervalMinutes" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="255" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="lbSecondsBetweenJobs" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="spSecondsBetweenJobs" min="-2" pref="90" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="lbTimeoutText" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="spTimeoutHours" min="-2" pref="90" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lbRestartRequired" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbSecondsBetweenJobsSeconds" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbTimeoutHours" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbInputScanIntervalMinutes" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="50" max="32767" 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"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbSecondsBetweenJobs" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="spSecondsBetweenJobs" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbSecondsBetweenJobsSeconds" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbTimeoutText" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="spTimeoutHours" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbTimeoutHours" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="cbTimeoutEnabled" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbInputScanInterval" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="spInputScanInterval" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbInputScanIntervalMinutes" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbRetriesAllowed" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="spMaximumRetryAttempts" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="lbRestartRequired" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" alignment="1" groupAlignment="3" attributes="0">
|
||||
<Component id="lbNumberOfThreads" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="numberOfFileIngestThreadsComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbSecondsBetweenJobs" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="spSecondsBetweenJobs" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbSecondsBetweenJobsSeconds" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbTimeoutText" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="spTimeoutHours" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbTimeoutHours" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="cbTimeoutEnabled" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbInputScanInterval" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="spInputScanInterval" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbInputScanIntervalMinutes" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbRetriesAllowed" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="spMaximumRetryAttempts" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbConcurrentJobsPerCase" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="spConcurrentJobsPerCase" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbNumberOfThreads" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="numberOfFileIngestThreadsComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
@ -229,6 +237,16 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbConcurrentJobsPerCase">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/configuration/Bundle.properties" key="AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/configuration/Bundle.properties" key="AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.toolTipText_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="cbTimeoutEnabled">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
@ -269,6 +287,16 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="spConcurrentJobsPerCase">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
|
||||
<SpinnerModel initial="3" maximum="100" minimum="1" numberType="java.lang.Integer" stepSize="1" type="number"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/configuration/Bundle.properties" key="AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="spMaximumRetryAttempts">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
|
||||
|
@ -63,6 +63,8 @@ class AdvancedAutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
initThreadCount();
|
||||
spSecondsBetweenJobs.setValue(AutoIngestUserPreferences.getSecondsToSleepBetweenCases());
|
||||
spMaximumRetryAttempts.setValue(AutoIngestUserPreferences.getMaxNumTimesToProcessImage());
|
||||
int maxJobsPerCase = AutoIngestUserPreferences.getMaxConcurrentJobsForOneCase();
|
||||
spConcurrentJobsPerCase.setValue(maxJobsPerCase);
|
||||
spInputScanInterval.setValue(AutoIngestUserPreferences.getMinutesOfInputScanInterval());
|
||||
spInputScanInterval.setEnabled(mode == AutoIngestSettingsPanel.OptionsUiMode.AIM);
|
||||
spSecondsBetweenJobs.setEnabled(mode == AutoIngestSettingsPanel.OptionsUiMode.AIM);
|
||||
@ -81,6 +83,7 @@ class AdvancedAutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
void store() {
|
||||
AutoIngestUserPreferences.setSecondsToSleepBetweenCases((int) spSecondsBetweenJobs.getValue());
|
||||
AutoIngestUserPreferences.setMaxNumTimesToProcessImage((int) spMaximumRetryAttempts.getValue());
|
||||
AutoIngestUserPreferences.setMaxConcurrentIngestNodesForOneCase((int) spConcurrentJobsPerCase.getValue());
|
||||
AutoIngestUserPreferences.setMinutesOfInputScanInterval((int) spInputScanInterval.getValue());
|
||||
UserPreferences.setNumberOfFileIngestThreads((Integer) numberOfFileIngestThreadsComboBox.getSelectedItem());
|
||||
boolean isChecked = cbTimeoutEnabled.isSelected();
|
||||
@ -120,9 +123,11 @@ class AdvancedAutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
lbInputScanInterval = new javax.swing.JLabel();
|
||||
lbRetriesAllowed = new javax.swing.JLabel();
|
||||
lbNumberOfThreads = new javax.swing.JLabel();
|
||||
lbConcurrentJobsPerCase = new javax.swing.JLabel();
|
||||
cbTimeoutEnabled = new javax.swing.JCheckBox();
|
||||
numberOfFileIngestThreadsComboBox = new javax.swing.JComboBox<>();
|
||||
lbRestartRequired = new javax.swing.JLabel();
|
||||
spConcurrentJobsPerCase = new javax.swing.JSpinner();
|
||||
spMaximumRetryAttempts = new javax.swing.JSpinner();
|
||||
spInputScanInterval = new javax.swing.JSpinner();
|
||||
spTimeoutHours = new javax.swing.JSpinner();
|
||||
@ -157,6 +162,9 @@ class AdvancedAutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
org.openide.awt.Mnemonics.setLocalizedText(lbNumberOfThreads, org.openide.util.NbBundle.getMessage(AdvancedAutoIngestSettingsPanel.class, "AdvancedAutoIngestSettingsPanel.lbNumberOfThreads.text")); // NOI18N
|
||||
lbNumberOfThreads.setToolTipText(org.openide.util.NbBundle.getMessage(AdvancedAutoIngestSettingsPanel.class, "AdvancedAutoIngestSettingsPanel.lbNumberOfThreads.toolTipText_1")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(lbConcurrentJobsPerCase, org.openide.util.NbBundle.getMessage(AdvancedAutoIngestSettingsPanel.class, "AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.text")); // NOI18N
|
||||
lbConcurrentJobsPerCase.setToolTipText(org.openide.util.NbBundle.getMessage(AdvancedAutoIngestSettingsPanel.class, "AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.toolTipText_1")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cbTimeoutEnabled, org.openide.util.NbBundle.getMessage(AdvancedAutoIngestSettingsPanel.class, "AdvancedAutoIngestSettingsPanel.cbTimeoutEnabled.text")); // NOI18N
|
||||
cbTimeoutEnabled.setToolTipText(org.openide.util.NbBundle.getMessage(AdvancedAutoIngestSettingsPanel.class, "AdvancedAutoIngestSettingsPanel.cbTimeoutEnabled.toolTipText")); // NOI18N
|
||||
cbTimeoutEnabled.addItemListener(new java.awt.event.ItemListener() {
|
||||
@ -180,6 +188,9 @@ class AdvancedAutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
lbRestartRequired.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/warning16.png"))); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(lbRestartRequired, org.openide.util.NbBundle.getMessage(AdvancedAutoIngestSettingsPanel.class, "AdvancedAutoIngestSettingsPanel.lbRestartRequired.text")); // NOI18N
|
||||
|
||||
spConcurrentJobsPerCase.setModel(new javax.swing.SpinnerNumberModel(3, 1, 100, 1));
|
||||
spConcurrentJobsPerCase.setToolTipText(org.openide.util.NbBundle.getMessage(AdvancedAutoIngestSettingsPanel.class, "AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.toolTipText")); // NOI18N
|
||||
|
||||
spMaximumRetryAttempts.setModel(new javax.swing.SpinnerNumberModel(2, 0, 9999999, 1));
|
||||
spMaximumRetryAttempts.setToolTipText(org.openide.util.NbBundle.getMessage(AdvancedAutoIngestSettingsPanel.class, "AdvancedAutoIngestSettingsPanel.lbRetriesAllowed.toolTipText_2")); // NOI18N
|
||||
|
||||
@ -210,70 +221,76 @@ class AdvancedAutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
.addGap(5, 5, 5)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addComponent(lbNumberOfThreads)
|
||||
.addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(lbRestartRequired)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addComponent(lbInputScanInterval)
|
||||
.addGap(49, 49, 49))
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addComponent(lbRetriesAllowed)
|
||||
.addGap(54, 54, 54))
|
||||
.addComponent(lbConcurrentJobsPerCase, javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(lbNumberOfThreads, javax.swing.GroupLayout.Alignment.LEADING))
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addComponent(lbInputScanInterval)
|
||||
.addGap(49, 49, 49))
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addComponent(lbRetriesAllowed)
|
||||
.addGap(54, 54, 54)))
|
||||
.addGap(0, 21, Short.MAX_VALUE)
|
||||
.addGap(0, 41, Short.MAX_VALUE)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(spInputScanInterval, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(spMaximumRetryAttempts, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addComponent(spMaximumRetryAttempts, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(spConcurrentJobsPerCase, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addComponent(lbSecondsBetweenJobs)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(spSecondsBetweenJobs, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addComponent(lbTimeoutText)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(spTimeoutHours, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(lbSecondsBetweenJobsSeconds)
|
||||
.addComponent(lbTimeoutHours)
|
||||
.addComponent(lbInputScanIntervalMinutes))
|
||||
.addContainerGap(255, Short.MAX_VALUE))))
|
||||
.addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addComponent(lbSecondsBetweenJobs)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(spSecondsBetweenJobs, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addComponent(lbTimeoutText)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(spTimeoutHours, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(lbRestartRequired)
|
||||
.addComponent(lbSecondsBetweenJobsSeconds)
|
||||
.addComponent(lbTimeoutHours)
|
||||
.addComponent(lbInputScanIntervalMinutes))
|
||||
.addContainerGap(50, Short.MAX_VALUE))
|
||||
);
|
||||
jPanelAutoIngestJobSettingsLayout.setVerticalGroup(
|
||||
jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbSecondsBetweenJobs)
|
||||
.addComponent(spSecondsBetweenJobs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbSecondsBetweenJobsSeconds))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbTimeoutText)
|
||||
.addComponent(spTimeoutHours, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbTimeoutHours))
|
||||
.addComponent(cbTimeoutEnabled))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbInputScanInterval)
|
||||
.addComponent(spInputScanInterval, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbInputScanIntervalMinutes))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbRetriesAllowed)
|
||||
.addComponent(spMaximumRetryAttempts, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(lbRestartRequired)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbNumberOfThreads)
|
||||
.addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createSequentialGroup()
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbSecondsBetweenJobs)
|
||||
.addComponent(spSecondsBetweenJobs, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbSecondsBetweenJobsSeconds))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbTimeoutText)
|
||||
.addComponent(spTimeoutHours, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbTimeoutHours))
|
||||
.addComponent(cbTimeoutEnabled))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbInputScanInterval)
|
||||
.addComponent(spInputScanInterval, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbInputScanIntervalMinutes))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbRetriesAllowed)
|
||||
.addComponent(spMaximumRetryAttempts, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbConcurrentJobsPerCase)
|
||||
.addComponent(spConcurrentJobsPerCase, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(jPanelAutoIngestJobSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbNumberOfThreads)
|
||||
.addComponent(numberOfFileIngestThreadsComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
@ -299,8 +316,8 @@ class AdvancedAutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
.addGap(20, 20, 20)
|
||||
.addComponent(spMainScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 106, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jPanelAutoIngestJobSettings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addComponent(jPanelAutoIngestJobSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGap(26, 26, 26))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
@ -319,6 +336,7 @@ class AdvancedAutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JCheckBox cbTimeoutEnabled;
|
||||
private javax.swing.JPanel jPanelAutoIngestJobSettings;
|
||||
private javax.swing.JLabel lbConcurrentJobsPerCase;
|
||||
private javax.swing.JLabel lbInputScanInterval;
|
||||
private javax.swing.JLabel lbInputScanIntervalMinutes;
|
||||
private javax.swing.JLabel lbNumberOfThreads;
|
||||
@ -329,6 +347,7 @@ class AdvancedAutoIngestSettingsPanel extends javax.swing.JPanel {
|
||||
private javax.swing.JLabel lbTimeoutHours;
|
||||
private javax.swing.JLabel lbTimeoutText;
|
||||
private javax.swing.JComboBox<Integer> numberOfFileIngestThreadsComboBox;
|
||||
private javax.swing.JSpinner spConcurrentJobsPerCase;
|
||||
private javax.swing.JSpinner spInputScanInterval;
|
||||
private javax.swing.JScrollPane spMainScrollPane;
|
||||
private javax.swing.JSpinner spMaximumRetryAttempts;
|
||||
|
@ -41,6 +41,7 @@ public final class AutoIngestUserPreferences {
|
||||
private static final String SHOW_TOOLS_WARNING = "ShowToolsWarning"; // NON-NLS
|
||||
private static final String MAX_NUM_TIMES_TO_PROCESS_IMAGE = "MaxNumTimesToAttemptToProcessImage"; // NON-NLS
|
||||
private static final int DEFAULT_MAX_TIMES_TO_PROCESS_IMAGE = 0;
|
||||
private static final String MAX_CONCURRENT_NODES_FOR_ONE_CASE = "MaxConcurrentNodesForOneCase"; // NON-NLS
|
||||
private static final String STATUS_DATABASE_LOGGING_ENABLED = "StatusDatabaseLoggingEnabled"; // NON-NLS
|
||||
private static final String LOGGING_DB_HOSTNAME_OR_IP = "LoggingHostnameOrIP"; // NON-NLS
|
||||
private static final String LOGGING_PORT = "LoggingPort"; // NON-NLS
|
||||
@ -257,6 +258,29 @@ public final class AutoIngestUserPreferences {
|
||||
ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, MAX_NUM_TIMES_TO_PROCESS_IMAGE, Integer.toString(retries));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get maximum number of concurrent ingest nodes allowable for one case at a
|
||||
* time.
|
||||
*
|
||||
* @return maximum number of concurrent nodes for one case. Default is 3.
|
||||
*/
|
||||
public static int getMaxConcurrentJobsForOneCase() {
|
||||
if (ModuleSettings.settingExists(UserPreferences.SETTINGS_PROPERTIES, MAX_CONCURRENT_NODES_FOR_ONE_CASE)) {
|
||||
return Integer.parseInt(ModuleSettings.getConfigSetting(UserPreferences.SETTINGS_PROPERTIES, MAX_CONCURRENT_NODES_FOR_ONE_CASE));
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get maximum number of concurrent ingest nodes allowable for one case at a
|
||||
* time.
|
||||
*
|
||||
* @param numberOfNodes the number of concurrent nodes to allow for one case
|
||||
*/
|
||||
public static void setMaxConcurrentIngestNodesForOneCase(int numberOfNodes) {
|
||||
ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, MAX_CONCURRENT_NODES_FOR_ONE_CASE, Integer.toString(numberOfNodes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status database logging checkbox state for automated ingest mode from
|
||||
* persistent storage.
|
||||
|
@ -89,6 +89,7 @@ AdvancedAutoIngestSettingsPanel.spMaximumRetryAttempts.toolTipText=The maximum n
|
||||
AdvancedAutoIngestSettingsPanel.lbRestartRequired.text=Application restart required to take effect.
|
||||
AdvancedAutoIngestSettingsPanel.cbTimeoutEnabled.toolTipText=Components that spawn potentially long-running processes optionally terminate those processes if the specified time out period has elapsed.
|
||||
AdvancedAutoIngestSettingsPanel.cbTimeoutEnabled.text=
|
||||
AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.text=Target concurrent jobs per case:
|
||||
AdvancedAutoIngestSettingsPanel.lbNumberOfThreads.text=Number of threads to use for file ingest:
|
||||
AdvancedAutoIngestSettingsPanel.lbRetriesAllowed.text=Maximum job retries allowed:
|
||||
AdvancedAutoIngestSettingsPanel.lbInputScanInterval.text=Interval between input scans:
|
||||
@ -102,6 +103,7 @@ AdvancedAutoIngestSettingsPanel.lbInputScanIntervalMinutes.toolTipText=
|
||||
AdvancedAutoIngestSettingsPanel.lbTimeoutHours.toolTipText=
|
||||
AdvancedAutoIngestSettingsPanel.lbRetriesAllowed.toolTipText_1=The maximum number of retries for crashed jobs.
|
||||
AdvancedAutoIngestSettingsPanel.lbRetriesAllowed.toolTipText_2=The maximum number of retries for crashed jobs.
|
||||
AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.toolTipText_1=A soft limit on the number of concurrent jobs per case when multiple cases are processed simultaneously.
|
||||
AdvancedAutoIngestSettingsPanel.lbNumberOfThreads.toolTipText_1=The number of threads running file level ingest modules.
|
||||
AdvancedAutoIngestSettingsPanel.numberOfFileIngestThreadsComboBox.toolTipText=The number of threads running file level ingest modules.
|
||||
NodeStatusLogPanel.tbDbName.toolTipText_1=Database name
|
||||
|
@ -102,6 +102,7 @@ public class SharedConfiguration {
|
||||
private boolean hideKnownFilesInViews;
|
||||
private boolean hideSlackFilesInDataSource;
|
||||
private boolean hideSlackFilesInViews;
|
||||
private boolean groupDatasources;
|
||||
private boolean keepPreferredViewer;
|
||||
|
||||
/**
|
||||
@ -206,6 +207,8 @@ public class SharedConfiguration {
|
||||
uploadHashDbSettings(remoteFolder);
|
||||
uploadFileExporterSettings(remoteFolder);
|
||||
uploadCentralRepositorySettings(remoteFolder);
|
||||
uploadObjectDetectionClassifiers(remoteFolder);
|
||||
uploadPythonModules(remoteFolder);
|
||||
|
||||
try {
|
||||
Files.deleteIfExists(uploadInProgress.toPath());
|
||||
@ -271,6 +274,8 @@ public class SharedConfiguration {
|
||||
downloadAndroidTriageSettings(remoteFolder);
|
||||
downloadFileExporterSettings(remoteFolder);
|
||||
downloadCentralRepositorySettings(remoteFolder);
|
||||
downloadObjectDetectionClassifiers(remoteFolder);
|
||||
downloadPythonModules(remoteFolder);
|
||||
|
||||
// Download general settings, then restore the current
|
||||
// values for the unshared fields
|
||||
@ -348,6 +353,7 @@ public class SharedConfiguration {
|
||||
fileIngestThreads = UserPreferences.numberOfFileIngestThreads();
|
||||
hideSlackFilesInDataSource = UserPreferences.hideSlackFilesInDataSourcesTree();
|
||||
hideSlackFilesInViews = UserPreferences.hideSlackFilesInViewsTree();
|
||||
groupDatasources = UserPreferences.groupItemsInTreeByDatasource();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -364,6 +370,7 @@ public class SharedConfiguration {
|
||||
UserPreferences.setNumberOfFileIngestThreads(fileIngestThreads);
|
||||
UserPreferences.setHideSlackFilesInDataSourcesTree(hideSlackFilesInDataSource);
|
||||
UserPreferences.setHideSlackFilesInViewsTree(hideSlackFilesInViews);
|
||||
UserPreferences.setGroupItemsInTreeByDatasource(groupDatasources);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -511,6 +518,71 @@ public class SharedConfiguration {
|
||||
throw new SharedConfigurationException(String.format("Failed to copy %s to %s", remoteFile.getAbsolutePath(), localSettingsFolder.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an entire local settings folder to the remote folder, deleting any existing files.
|
||||
*
|
||||
* @param localFolder The local folder to copy
|
||||
* @param remoteBaseFolder The remote folder that will hold a copy of the original folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void copyLocalFolderToRemoteFolder(File localFolder, File remoteBaseFolder) throws SharedConfigurationException {
|
||||
logger.log(Level.INFO, "Uploading {0} to {1}", new Object[]{localFolder.getAbsolutePath(), remoteBaseFolder.getAbsolutePath()});
|
||||
|
||||
File newRemoteFolder = new File(remoteBaseFolder, localFolder.getName());
|
||||
|
||||
if(newRemoteFolder.exists()) {
|
||||
try {
|
||||
FileUtils.deleteDirectory(newRemoteFolder);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to delete remote folder {0}", newRemoteFolder.getAbsolutePath());
|
||||
throw new SharedConfigurationException(String.format("Failed to delete remote folder {0}", newRemoteFolder.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
FileUtils.copyDirectoryToDirectory(localFolder, remoteBaseFolder);
|
||||
} catch (IOException ex) {
|
||||
throw new SharedConfigurationException(String.format("Failed to copy %s to %s", localFolder, remoteBaseFolder.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an entire remote settings folder to the local folder, deleting any existing files.
|
||||
* No error if the remote folder does not exist.
|
||||
*
|
||||
* @param localFolder The local folder that will be overwritten.
|
||||
* @param remoteBaseFolder The remote folder holding the folder that will be copied
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void copyRemoteFolderToLocalFolder(File localFolder, File remoteBaseFolder) throws SharedConfigurationException {
|
||||
logger.log(Level.INFO, "Downloading {0} from {1}", new Object[]{localFolder.getAbsolutePath(), remoteBaseFolder.getAbsolutePath()});
|
||||
|
||||
// Clean out the local folder regardless of whether the remote version exists. leave the
|
||||
// folder in place since Autopsy expects it to exist.
|
||||
if(localFolder.exists()) {
|
||||
try {
|
||||
FileUtils.cleanDirectory(localFolder);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to delete files from local folder {0}", localFolder.getAbsolutePath());
|
||||
throw new SharedConfigurationException(String.format("Failed to delete files from local folder {0}", localFolder.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
File remoteSubFolder = new File(remoteBaseFolder, localFolder.getName());
|
||||
if(! remoteSubFolder.exists()) {
|
||||
logger.log(Level.INFO, "{0} does not exist", remoteSubFolder.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
FileUtils.copyDirectory(remoteSubFolder, localFolder);
|
||||
} catch (IOException ex) {
|
||||
throw new SharedConfigurationException(String.format("Failed to copy %s from %s", localFolder, remoteBaseFolder.getAbsolutePath()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the basic set of auto-ingest settings to the shared folder.
|
||||
@ -828,6 +900,58 @@ public class SharedConfiguration {
|
||||
copyToLocalFolder(AUTO_INGEST_PROPERTIES, moduleDirPath, remoteFolder, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the object detection classifiers.
|
||||
*
|
||||
* @param remoteFolder Shared settings folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void uploadObjectDetectionClassifiers(File remoteFolder) throws SharedConfigurationException {
|
||||
publishTask("Uploading object detection classfiers");
|
||||
File classifiersFolder = new File(PlatformUtil.getObjectDetectionClassifierPath());
|
||||
copyLocalFolderToRemoteFolder(classifiersFolder, remoteFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the object detection classifiers.
|
||||
*
|
||||
* @param remoteFolder Shared settings folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void downloadObjectDetectionClassifiers(File remoteFolder) throws SharedConfigurationException {
|
||||
publishTask("Downloading object detection classfiers");
|
||||
File classifiersFolder = new File(PlatformUtil.getObjectDetectionClassifierPath());
|
||||
copyRemoteFolderToLocalFolder(classifiersFolder, remoteFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the Python modules.
|
||||
*
|
||||
* @param remoteFolder Shared settings folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void uploadPythonModules(File remoteFolder) throws SharedConfigurationException {
|
||||
publishTask("Uploading python modules");
|
||||
File classifiersFolder = new File(PlatformUtil.getUserPythonModulesPath());
|
||||
copyLocalFolderToRemoteFolder(classifiersFolder, remoteFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the Python modules.
|
||||
*
|
||||
* @param remoteFolder Shared settings folder
|
||||
*
|
||||
* @throws SharedConfigurationException
|
||||
*/
|
||||
private void downloadPythonModules(File remoteFolder) throws SharedConfigurationException {
|
||||
publishTask("Downloading python modules");
|
||||
File classifiersFolder = new File(PlatformUtil.getUserPythonModulesPath());
|
||||
copyRemoteFolderToLocalFolder(classifiersFolder, remoteFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload settings and hash databases to the shared folder. The general
|
||||
* algorithm is: - Copy the general settings in hashsets.xml - For each hash
|
||||
|
@ -43,7 +43,6 @@ abstract class AdHocSearchPanel extends javax.swing.JPanel {
|
||||
private final String keywordSearchErrorDialogHeader = org.openide.util.NbBundle.getMessage(this.getClass(), "AbstractKeywordSearchPerformer.search.dialogErrorHeader");
|
||||
protected int filesIndexed;
|
||||
private final Map<Long, String> dataSourceMap = new HashMap<>();
|
||||
private final List<String> toolTipList = new ArrayList<>();
|
||||
private List<DataSource> dataSources = new ArrayList<>();
|
||||
private final DefaultListModel<String> dataSourceListModel = new DefaultListModel<>();
|
||||
|
||||
@ -153,14 +152,12 @@ abstract class AdHocSearchPanel extends javax.swing.JPanel {
|
||||
*/
|
||||
synchronized List<String> getDataSourceArray() {
|
||||
List<String> dsList = new ArrayList<>();
|
||||
toolTipList.clear();
|
||||
Collections.sort(this.dataSources, (DataSource ds1, DataSource ds2) -> ds1.getName().compareTo(ds2.getName()));
|
||||
for (DataSource ds : dataSources) {
|
||||
String dsName = ds.getName();
|
||||
File dataSourceFullName = new File(dsName);
|
||||
String displayName = dataSourceFullName.getName();
|
||||
dataSourceMap.put(ds.getId(), displayName);
|
||||
toolTipList.add(dsName);
|
||||
dsList.add(displayName);
|
||||
}
|
||||
return dsList;
|
||||
@ -183,14 +180,6 @@ abstract class AdHocSearchPanel extends javax.swing.JPanel {
|
||||
Map<Long, String> getDataSourceMap() {
|
||||
return dataSourceMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of tooltip text for data source
|
||||
* @return A list of tool tips
|
||||
*/
|
||||
List<String> getDataSourceToolTipList() {
|
||||
return toolTipList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of DataSourceListModel
|
||||
|
@ -73,22 +73,6 @@ class DropdownListSearchPanel extends AdHocSearchPanel {
|
||||
dataSourceList.addListSelectionListener((ListSelectionEvent evt) -> {
|
||||
firePropertyChange(Bundle.DropdownSingleTermSearchPanel_selected(), null, null);
|
||||
});
|
||||
dataSourceList.addMouseMotionListener(new MouseMotionListener() {
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent evt) {
|
||||
//Unused by now
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent evt) {
|
||||
JList<String> dsList = (JList<String>) evt.getSource();
|
||||
int index = dsList.locationToIndex(evt.getPoint());
|
||||
if (index > -1) {
|
||||
dsList.setToolTipText(getDataSourceToolTipList().get(index));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static synchronized DropdownListSearchPanel getDefault() {
|
||||
|
@ -88,22 +88,6 @@ public class DropdownSingleTermSearchPanel extends AdHocSearchPanel {
|
||||
this.dataSourceList.addListSelectionListener((ListSelectionEvent evt) -> {
|
||||
firePropertyChange(Bundle.DropdownSingleTermSearchPanel_selected(), null, null);
|
||||
});
|
||||
this.dataSourceList.addMouseMotionListener(new MouseMotionListener() {
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent evt) {
|
||||
//Unused by now
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent evt) {
|
||||
JList<String> DsList = (JList<String>) evt.getSource();
|
||||
int index = DsList.locationToIndex(evt.getPoint());
|
||||
if (index > -1) {
|
||||
DsList.setToolTipText(getDataSourceToolTipList().get(index));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,7 +27,7 @@ import org.apache.solr.common.SolrInputDocument;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||
import org.sleuthkit.autopsy.keywordsearch.Chunker.Chunk;
|
||||
@ -237,9 +237,9 @@ class Ingester {
|
||||
|
||||
try {
|
||||
//TODO: consider timeout thread, or vary socket timeout based on size of indexed content
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Index chunk");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Index chunk");
|
||||
solrServer.addDocument(updateDoc);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
uncommitedIngests = true;
|
||||
|
||||
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
|
||||
|
@ -70,7 +70,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@ -710,9 +710,9 @@ public class Server {
|
||||
if (null == currentCore) {
|
||||
throw new NoOpenCoreException();
|
||||
}
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Index chunk");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Index chunk");
|
||||
currentCore.addDocument(doc);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
} finally {
|
||||
currentCoreLock.readLock().unlock();
|
||||
}
|
||||
@ -781,9 +781,9 @@ public class Server {
|
||||
IndexingServerProperties properties = getMultiUserServerProperties(theCase.getCaseDirectory());
|
||||
currentSolrServer = new HttpSolrServer("http://" + properties.getHost() + ":" + properties.getPort() + "/solr"); //NON-NLS
|
||||
}
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Connectivity check");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Connectivity check");
|
||||
connectToSolrServer(currentSolrServer);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
|
||||
} catch (SolrServerException | IOException ex) {
|
||||
throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg", ex.getLocalizedMessage()), ex);
|
||||
@ -1325,13 +1325,13 @@ public class Server {
|
||||
* @throws IOException
|
||||
*/
|
||||
void connectToSolrServer(HttpSolrServer solrServer) throws SolrServerException, IOException {
|
||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Connectivity check");
|
||||
TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Connectivity check");
|
||||
CoreAdminRequest statusRequest = new CoreAdminRequest();
|
||||
statusRequest.setCoreName( null );
|
||||
statusRequest.setAction( CoreAdminParams.CoreAdminAction.STATUS );
|
||||
statusRequest.setIndexInfoNeeded(false);
|
||||
statusRequest.process(solrServer);
|
||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
||||
HealthMonitor.submitTimingMetric(metric);
|
||||
}
|
||||
|
||||
/**
|
||||
|
32
NEWS.txt
@ -1,3 +1,35 @@
|
||||
---------------- VERSION 4.8.0 --------------
|
||||
New Features:
|
||||
- The case tree view can now be grouped by data source.
|
||||
- Added a common files search tool that finds all instances of a file in a case.
|
||||
- Text extraction optionally includes optical character recognition (OCR).
|
||||
- Data source(s) filter added to ad hoc keyword search and file search by
|
||||
attributes.
|
||||
- SQLite tables can be now be exported to CSV files.
|
||||
- User defined tags now appear first in tagging menus.
|
||||
- Eliminated one tagging sub menu layer for faster tagging.
|
||||
- Added Replace Tag item to tagging menus (shortcut for delete tag, add tag).
|
||||
- The Other Occurrences content viewer now shows matches in the current case.
|
||||
- A listing of cases in the central repository is displayed by the
|
||||
central repository options panel.
|
||||
- An interesting file artifact is now created when a "zip bomb" is detected.
|
||||
- Text and queries sent to Solr are now normalized to handle diacritics,
|
||||
ligatures, narrow and wide width Japanese characters, etc.
|
||||
- An object detection ingest module that uses OpenCV and user-supplied
|
||||
classifiers has been added to the "experimental" Net Beans Module (NBM).
|
||||
- A data source processor that runs Volatility on a memory image has been
|
||||
added to the "experimental" NBM.
|
||||
- Comments can be added to all files (file correlation properties) recorded
|
||||
in the central repository using a results view context menu item.
|
||||
- Comments can be added to all correlation properties recorded
|
||||
in the central repository using an Other Occurrences results content viewer
|
||||
context menu item.
|
||||
|
||||
Bug Fixes:
|
||||
- Expanding the case tree is more efficient.
|
||||
- Improved "zip bomb" detection.
|
||||
- Assorted small bug fixes are included.
|
||||
|
||||
---------------- VERSION 4.7.0 --------------
|
||||
New Features:
|
||||
- A graph visualization was added to the Communications tool to make it easier to find messages and relationships.
|
||||
|
@ -1,5 +1,5 @@
|
||||
#Updated by build script
|
||||
#Mon, 19 Mar 2018 11:17:11 -0700
|
||||
#Mon, 25 Jun 2018 17:19:36 -0400
|
||||
LBL_splash_window_title=Starting Autopsy
|
||||
SPLASH_HEIGHT=314
|
||||
SPLASH_WIDTH=538
|
||||
@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18
|
||||
SplashRunningTextColor=0x0
|
||||
SplashRunningTextFontSize=19
|
||||
|
||||
currentVersion=Autopsy 4.6.0
|
||||
currentVersion=Autopsy 4.8.0
|
||||
|
@ -1,4 +1,4 @@
|
||||
#Updated by build script
|
||||
#Fri, 09 Mar 2018 13:03:41 -0700
|
||||
CTL_MainWindow_Title=Autopsy 4.6.0
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 4.6.0
|
||||
#Mon, 25 Jun 2018 17:19:36 -0400
|
||||
CTL_MainWindow_Title=Autopsy 4.8.0
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 4.8.0
|
||||
|
@ -72,7 +72,7 @@ In general all three types of keyword searches will work as expected but the fea
|
||||
|
||||
\section ad_hoc_kw_search Keyword Search
|
||||
|
||||
Individual keyword or regular expressions can quickly be searched using the search text box widget. You can select "Exact Match", "Substring Match" and "Regular Expression" match. See the earlier \ref ad_hoc_kw_types_section section for information on each keyword type. The search can be restricted to only certain data sources by selecting the checkbox near the bottom and then highlighting the data sources to search within. Multiple data sources can be selected used shift+right click or control+right click.
|
||||
Individual keyword or regular expressions can quickly be searched using the search text box widget. You can select "Exact Match", "Substring Match" and "Regular Expression" match. See the earlier \ref ad_hoc_kw_types_section section for information on each keyword type. The search can be restricted to only certain data sources by selecting the checkbox near the bottom and then highlighting the data sources to search within. Multiple data sources can be selected used shift+left click or control+left click.
|
||||
|
||||
\image html keyword-search-bar.PNG
|
||||
|
||||
@ -84,7 +84,7 @@ Results will be opened in a separate Results Viewer for every search executed an
|
||||
|
||||
In addition to being selected during ingest, keyword lists can also be run through the Keyword Lists button. For information on setting up these keyword lists, see the \ref keywordListsTab section of the ingest module documentation.
|
||||
|
||||
Lists created using the Keyword Search Configuration Dialog can be manually searched by the user by pressing on the 'Keyword Lists' button and selecting the check boxes corresponding to the lists to be searched. The search can be restricted to only certain data sources by selecting the checkbox near the bottom and then highlighting the data sources to search within. Multiple data sources can be selected used shift+right click or control+right click. Once everything has been configured, press "Search" to begin the search.
|
||||
Lists created using the Keyword Search Configuration Dialog can be manually searched by the user by pressing on the 'Keyword Lists' button and selecting the check boxes corresponding to the lists to be searched. The search can be restricted to only certain data sources by selecting the checkbox near the bottom and then highlighting the data sources to search within. Multiple data sources can be selected used shift+left click or control+left click. Once everything has been configured, press "Search" to begin the search.
|
||||
|
||||
\image html keyword-search-list.PNG
|
||||
|
||||
|
@ -7,11 +7,11 @@ It is a combination of an ingest module that extracts, stores, and compares prop
|
||||
properties, a database that stores these properties, and an additional panel in Autopsy to display other instances of each
|
||||
property. The central repository database can either be SQLite or PostgreSQL.
|
||||
|
||||
The following are some use cases for the Central Repository:
|
||||
The following are some use cases for the central repository:
|
||||
- <b>Finding Other Instances of a Property</b>
|
||||
- If you find a file or Autopsy artifact (such as a Web History item), there is a content viewer in the bottom right that will show you other cases that had this same file or that had items with the same feature (such as Domain name). You will also be able to see what other data sources in the same case had this feature.
|
||||
- If you navigate to a file or Autopsy artifact (such as a Web History item), there is a content viewer in the bottom right that will show you other instances of this property across the data stored in the central repository.
|
||||
- <b>Alerting When Previously Notable Properties Occur</b>
|
||||
- You can use the Central Repository to record which properties were associated with files and artifacts that were evidence (or notable). Once these properties have been tagged as notable they will be added to the Interesting Items section of the tree when seen again in any future cases.
|
||||
- You can use the central repository to record which properties were associated with files and artifacts that were evidence (or notable). Once these properties have been tagged as notable they will be added to the Interesting Items section of the tree when seen again in any future cases.
|
||||
- <b>Storing Hash Sets</b>
|
||||
- You can create and import hash sets into the central repository instead of using local copies in the \ref hash_db_page "Hash Lookup module". These hash sets are functionally equivalent to local hash sets but can be shared among multiple analysts (when using a PostgreSQL central repository).
|
||||
|
||||
@ -24,13 +24,13 @@ The following are some use cases for the Central Repository:
|
||||
|
||||
\section cr_setup Setup
|
||||
|
||||
To start, open the main options panel and select the Central Repository icon.
|
||||
To start, open the main options panel and select the "Central Repository" icon.
|
||||
|
||||
\image html central_repo_options.png
|
||||
|
||||
\subsection cr_db_setup Setting up the Database
|
||||
|
||||
On the Central Repository options panel, check the 'Use a Central Repository' option and then click the Configure button to set up a database. There are two options here:
|
||||
On the central repository options panel, check the 'Use a Central Repository' option and then click the Configure button to set up a database. There are two options here:
|
||||
- <b>SQLite</b> - This option stores the database in a file. It should only be used when a single client will be accessing the database.
|
||||
- <b>PostgreSQL</b> - This option uses a database server running either on the user's host or a remote server. This option must be used if multiple users will be using the same database.
|
||||
|
||||
@ -89,7 +89,13 @@ Organizations are stored in the central repository and contain contact informati
|
||||
One default org, "Not Specified" will always be present in the list. New organizations can be created, edited, and deleted through the appropriate buttons. Note that any organization that is currently in use by a case or hash set can not be deleted. All fields apart from the organization name are optional.
|
||||
|
||||
\image html central_repo_new_org.png
|
||||
|
||||
|
||||
\subsection cr_show_cases Show Cases
|
||||
|
||||
Displays a list of all cases that are in the central repository database.
|
||||
|
||||
\image html central_repo_details.png
|
||||
|
||||
\section cr_using_repo Using the Central Repository
|
||||
|
||||
\subsection cr_ingest_module Correlation Engine Module
|
||||
@ -103,17 +109,20 @@ other cases/data sources where the Correlation Engine was run.
|
||||
|
||||
\subsection cr_tagging Tagging Files and Artifacts
|
||||
|
||||
Any file or artifact that a user tags with a tag with notable set will be added
|
||||
to the database as a file or artifact of interest. By default, there will be a tag named "Notable Item" that can be used for this purpose. See the \ref tagging_page "Tagging page" for more information on creating additional tags with notable status. Any future data source ingest (where this module is enabled)
|
||||
will use those notable files or artifacts in a similar manner as a Known Bad hash set, causing matching files from that
|
||||
ingest to be added to the Interesting Artifacts list in that currently open case.
|
||||
Tagging a file or artifact with a "notable" tag will change its associated property in the central repository to notable as well.
|
||||
By default, there will be a tag named "Notable Item" that can be used for this purpose. See the \ref tagging_page "Tagging page" for more information on creating additional tags with notable status.
|
||||
Any future data source ingest (where this module is enabled)
|
||||
will use those notable properties in a similar manner as a Known Bad hash set, causing matching files and artifacts from that
|
||||
ingest to be added to the Interesting Items list in that currently open case.
|
||||
|
||||
\image html central_repo_tag_file.png
|
||||
|
||||
If a tag is accidentally added to a file or artifact, it can be removed though the context menu. This will remove its
|
||||
notable status in the Central Repository.
|
||||
If a tag is accidentally added to a file or artifact, it can be removed though the context menu. This will remove its property's
|
||||
notable status in the central repository.
|
||||
|
||||
If you would like to prevent the Interesting Items from being created in a particular case, you can disable the flagging through the run time ingest properties. Note that this only disables the Interesting Item results - all files and artifacts are still added to the central repository.
|
||||
If you would like to prevent the Interesting Items from being created in a particular case, you can disable the flagging
|
||||
through the run time ingest properties. Note that this only disables the Interesting Item results - all properties
|
||||
are still added to the central repository.
|
||||
|
||||
\image html central_repo_disable_flagging.png
|
||||
|
||||
@ -125,11 +134,16 @@ Results from enabling a central repository and running the Correlation Engine In
|
||||
|
||||
\subsection cr_content_viewer Content Viewer
|
||||
|
||||
The \ref content_viewer_page panel is where previous instances of properties are displayed. This module adds a new tab to the Content Viewer. The tab for this module is called "Other Occurrences". It can display data that is found in other cases, other data sources for the same case, or imported global artifacts.
|
||||
The \ref content_viewer_page panel is where previous instances of properties are displayed. Without a central repository enabled,
|
||||
this "Other Occurrences" panel will show files with hashes matching the selected file within the current case. Enabling a central
|
||||
repository allows this panel to also display matching properties stored in the database, and adds some functionality to the row.
|
||||
Note that the Correlation Engine Ingest Module does not have to have been run on the current data source to see correlated
|
||||
properties from the central repository. If the selected file or artifact is associated by one of the supported Correlation Types,
|
||||
to one or more properties in the database, the associated properties will be displayed. Note: the Content
|
||||
Viewer will display ALL associated properties available in the database. It ignores the user's enabled/disabled Correlation Properties.
|
||||
|
||||
If at least one other case or data source has been ingested with this module enabled, there is a potential that data will be displayed in the Other Occurrences content viewer. Note that the Correlation Engine Ingest Module does not have to have been run on the current data source to see correlated files from other cases/data sources. If the selected file or artifact is associated by one of the supported Correlation Types, to one or more file(s) or artifact(s) in the database, the associated files/artifacts will be displayed. Note: the Content Viewer will display ALL associated files and artifacts available in the database. It ignores the user's enabled/disabled Correlation Properties.
|
||||
|
||||
By default, the rows in the content viewer will have background colors to indicate if they are known to be of interest. Files/artifacts that are notable will have a Red background, all others will have a White background.
|
||||
By default, the rows in the content viewer will have background colors to indicate if they are known to be of interest. Properties that are notable
|
||||
will have a Red background, all others will have a White background.
|
||||
|
||||
\image html central_repo_content_viewer.png
|
||||
|
||||
@ -141,6 +155,7 @@ This menu has several options.
|
||||
-# Export Selected Rows to CSV
|
||||
-# Show Case Details
|
||||
-# Show Frequency
|
||||
-# Add/Edit Comment
|
||||
|
||||
<b>Select All</b>
|
||||
|
||||
@ -170,19 +185,29 @@ the Case -> Case Properties menu.
|
||||
|
||||
<b>Show Frequency</b>
|
||||
|
||||
This shows how common the selected file is. The value is the percentage of case/data source tuples that have the selected file or artifact.
|
||||
This shows how common the selected file is. The value is the percentage of case/data source tuples that have the selected property.
|
||||
|
||||
<b>Add/Edit Comment</b>
|
||||
|
||||
This allows you to add a comment for this entry or edit an existing comment. If you want instead to edit the comment of the originally selected node, it can be done by right clicking on the original item in the result viewer and selecting "Add/Edit Central Repository Comment".
|
||||
|
||||
\image html central_repo_comment_menu.png
|
||||
|
||||
\subsection cr_interesting_items Interesting Items
|
||||
|
||||
In the Results tree of an open case is an entry called Interesting Items. When this module is enabled, all of the enabled Correlatable Properties will cause matching files to be added to this Interesting Items tree during ingest.
|
||||
In the Results tree of an open case is an entry called Interesting Items. When this module is enabled, all of the enabled
|
||||
Correlatable Properties will cause matching files and artifacts to be added to this Interesting Items tree during ingest.
|
||||
|
||||
\image html central_repo_interesting_items.png
|
||||
|
||||
As an example, if the Files Correlatable Property is enabled, and the ingest is currently processing a file, for example "badfile.exe", and the MD5 hash for that file already exists in the database as a notable file, then an entry in the Interesting Items tree will be added for the current instance of "badfile.exe" in the data source currently being ingested.
|
||||
As an example, suppose the Files Correlatable Property is enabled and the ingest is currently processing a file "badfile.exe", and the MD5 hash
|
||||
for that file already exists in the database as a notable file property. In this case an entry in the Interesting Items tree will be added for
|
||||
the current instance of "badfile.exe" in the data source currently being ingested.
|
||||
|
||||
The same type of thing will happen for each enabled Correlatable Property.
|
||||
|
||||
In the case of the phone number correlatable type, the Interesting Items tree will start a sub-tree for each phone number. The sub-tree will then contain each instance of that notable phone number.
|
||||
In the case of the phone number correlatable type, the Interesting Items tree will start a sub-tree for each phone number. The sub-tree will
|
||||
then contain each instance of that notable phone number.
|
||||
|
||||
|
||||
|
||||
|
23
docs/doxygen-user/common_files.dox
Normal file
@ -0,0 +1,23 @@
|
||||
/*! \page common_files_page Common Files Search
|
||||
|
||||
\section common_files_overview Overview
|
||||
|
||||
The common files feature allows you to search for multiple copies of the same file in different data sources within a case.
|
||||
|
||||
\section common_files_usage Usage
|
||||
|
||||
To start, go to Tools->Common Files Search to bring up the following dialog:
|
||||
|
||||
\image html common_files_dialog.png
|
||||
|
||||
You can choose to find any files with multiple copies in the whole case, or specify that at least one of the copies has to be in the selected data source(s).
|
||||
|
||||
\image html common_files_data_source.png
|
||||
|
||||
You can also choose to restrict the search to only pictures and videos and/or documents.
|
||||
|
||||
Once the search is run, the matching files are displayed in the results tab. The results are grouped by how many matching files were found and then grouped by hash.
|
||||
|
||||
\image html common_files_results.png
|
||||
|
||||
*/
|
@ -28,7 +28,7 @@ It will display most image types:
|
||||
|
||||
\image html content_viewer_app_image.png
|
||||
|
||||
It also allows you to browse SQLite tables:
|
||||
It also allows you to browse SQLite tables and export their contents as CSV:
|
||||
|
||||
\image html content_viewer_app_sqlite.png
|
||||
|
||||
@ -64,7 +64,7 @@ The Results tab is active when selecting entries that are part of the Results tr
|
||||
|
||||
\section cv_other_occurrences Other Occurrences
|
||||
|
||||
The Other Occurrences tab shows what other cases/data sources this file or result has appeared in. The \ref central_repo_page must be enabled to access this tab. See the \ref cr_content_viewer section for more information.
|
||||
The Other Occurrences tab shows other instances of this file or result. Enabling the \ref central_repo_page adds additional functionality to this tab. See the \ref cr_content_viewer section for more information.
|
||||
|
||||
\image html content_viewer_other_occurrences.png
|
||||
|
||||
|
19
docs/doxygen-user/experimental.dox
Normal file
@ -0,0 +1,19 @@
|
||||
/*! \page experimental_page Experimental Module
|
||||
|
||||
\section exp_overview Overview
|
||||
|
||||
The Experimental module, as the name implies, contains code that is not yet part of the official Autopsy release. These experimental features can be used but may be less polished than other features and will have less documentation. These modules may be changed at any time.
|
||||
|
||||
\section exp_setup Enabling the Experimental Module
|
||||
|
||||
To start, go to Tools->Plugins and select the "Installed" tab, then check the box next to "Experimental" and click "Activate" and go throught the next couple of screens. A reset should not be required.
|
||||
|
||||
\image html experimental_plugins_menu.png
|
||||
|
||||
\section exp_features Current Experimental Features
|
||||
|
||||
- Auto Ingest
|
||||
- \ref object_detection_page
|
||||
- \ref volatility_dsp_page
|
||||
|
||||
*/
|
@ -32,7 +32,7 @@ Search for all files and directory whose "date property" is within the date rang
|
||||
Search for all files and directory whose known status is recognized as either Unknown, Known, or Known Bad. For more on Known Status, see the \ref hash_db_page.
|
||||
To use any of these filters, check the box next to the category and click "Search" button to start the search process. The result will show up in the "Result Viewer".
|
||||
\li Data Source:
|
||||
Search only within the specified data source instead of the entire case. Note that multiple data sources can be selected by using shift+right mouse button or control+right mouse button.
|
||||
Search only within the specified data source instead of the entire case. Note that multiple data sources can be selected by holding SHIFT or CTRL while selecting.
|
||||
|
||||
Here's a contrived example where we try to get all the directories and files whose name contains "hello", has a size greater than 1000 Bytes, is in JPEG format, was created between 06/01/2018 and
|
||||
06/08/2017 (in GMT-5 timezone), is an unknown file, has a hash of 1127F348BD4303A4C3D1D587C807B49F, and appears in data source "image3.vhd":
|
||||
|
@ -1,5 +1,5 @@
|
||||
<hr/>
|
||||
<p><i>Copyright © 2012-2016 Basis Technology. Generated on $date<br/>
|
||||
<p><i>Copyright © 2012-2018 Basis Technology. Generated on $date<br/>
|
||||
This work is licensed under a
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.
|
||||
</i></p>
|
||||
|
BIN
docs/doxygen-user/images/central_repo_comment_menu.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
docs/doxygen-user/images/central_repo_details.png
Normal file
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 44 KiB |
BIN
docs/doxygen-user/images/common_files_data_source.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
docs/doxygen-user/images/common_files_dialog.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
docs/doxygen-user/images/common_files_results.png
Normal file
After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 34 KiB |
BIN
docs/doxygen-user/images/experimental_plugins_menu.png
Normal file
After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 34 KiB |
BIN
docs/doxygen-user/images/object_detection_classifier_dir.PNG
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/doxygen-user/images/object_detection_results.PNG
Normal file
After Width: | Height: | Size: 175 KiB |
BIN
docs/doxygen-user/images/object_detection_warning.PNG
Normal file
After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 53 KiB |
BIN
docs/doxygen-user/images/tagging_new_tag.PNG
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
docs/doxygen-user/images/ui_layout_group_tree.PNG
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
docs/doxygen-user/images/volatility_dsp_config.PNG
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
docs/doxygen-user/images/volatility_dsp_interesting_items.PNG
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
docs/doxygen-user/images/volatility_dsp_module_output.PNG
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
docs/doxygen-user/images/volatility_dsp_select.png
Normal file
After Width: | Height: | Size: 37 KiB |
@ -47,6 +47,7 @@ The following topics are available here:
|
||||
- \subpage stix_page
|
||||
- \subpage central_repo_page
|
||||
- \subpage communications_page
|
||||
- \subpage common_files_page
|
||||
- \subpage logs_and_output_page
|
||||
- Reporting
|
||||
- \subpage tagging_page
|
||||
@ -63,6 +64,7 @@ The following topics are available here:
|
||||
- \subpage multiuser_page
|
||||
- \subpage live_triage_page
|
||||
- \subpage advanced_page
|
||||
- \subpage experimental_page
|
||||
|
||||
If the topic you need is not listed, refer to the <a href="http://wiki.sleuthkit.org/index.php?title=Autopsy_User%27s_Guide">Autopsy Wiki</a> or join the <a href="https://lists.sourceforge.net/lists/listinfo/sleuthkit-users">SleuthKit User List</a> at SourceForge.
|
||||
|
||||
|
25
docs/doxygen-user/object_detection.dox
Normal file
@ -0,0 +1,25 @@
|
||||
/*! \page object_detection_page Object Detection
|
||||
|
||||
\section object_overview Overview
|
||||
|
||||
The Object Detection module uses OpenCV to try to detect objects in images.
|
||||
|
||||
\section object_setup Setup
|
||||
|
||||
To start, you will need some classifiers, which are xml files. Autopsy can not create classifiers - do a web search for "train OpenCV classifiers" to find information on how to make classifiers, or visit the <a href="https://docs.opencv.org/2.4/doc/user_guide/ug_traincascade.html">OpenCV page</a>.
|
||||
|
||||
Once you have your set of classifiers, copy them into the folder "object_detection_classifiers" in your Autopsy user directory. On Windows, this will normally be found in "C:\Users\<uesr name>\AppData\Roaming\Autopsy". If you can't find the directory, try to run the module as described in the next section. The warning message will tell you where the module expects the classifiers to be.
|
||||
|
||||
\image html object_detection_classifier_dir.PNG
|
||||
|
||||
\section object_running Running the Ingest Module
|
||||
|
||||
You can run the object detection module by enabling it when running ingest. There is no further configuration needed. If you have not added any classifiers, or have put the classifiers in the wrong place, you'll see a warning bubble.
|
||||
|
||||
\image html object_detection_warning.PNG
|
||||
|
||||
Any files that had objects detected in them will appear in under "Objects Detected". The result tree will show which classifiers matched each image.
|
||||
|
||||
\image html object_detection_results.PNG
|
||||
|
||||
*/
|
@ -12,11 +12,16 @@ Which to choose depends upon the context and what you desire in the final report
|
||||
|
||||
\image html tagging-1.PNG
|
||||
|
||||
Once you have chosen to tag the file or the result, there are two more options:
|
||||
- Quick Tag -- use this if you just want the tag
|
||||
At this point there are three options:
|
||||
- Use one of the existing tags to add it to the file/result without a comment
|
||||
- Tag and Comment -- use this if you need to add a comment about this tag
|
||||
|
||||
\image html tagging-2.PNG
|
||||
|
||||
- New tag -- Create a new tag and add it to the file/result
|
||||
|
||||
\image html tagging_new_tag.png
|
||||
|
||||
<br>
|
||||
There are several default tag names:
|
||||
- Bookmark - Default tag for marking files of interest
|
||||
@ -24,9 +29,7 @@ There are several default tag names:
|
||||
- Follow Up - Default tag for marking files to follow up on
|
||||
- Notable item - Default tag for indicating that an item should be marked as notable in the central repository
|
||||
|
||||
You can also create custom tag names. These tag names will be automatically saved for future use. Choose a tag from the list you have created, or create a "New Tag".
|
||||
|
||||
\image html tagging-3.PNG
|
||||
You can also create custom tag names. These tag names will be automatically saved for future use and will be displayed above the default tag names.
|
||||
|
||||
If you just want to tag the item with the default "Bookmark" tag, you can also use the keyboard shortcut control+B instead of going through the menus.
|
||||
|
||||
|