Merge pull request #3921 from raman-bt/develop
Merging Develop into image-gallery-db-migration
@ -64,13 +64,14 @@ public final class ReplaceBlackboardArtifactTagAction extends ReplaceTagAction<B
|
|||||||
*
|
*
|
||||||
* @param oldArtifactTag tag to be replaced
|
* @param oldArtifactTag tag to be replaced
|
||||||
* @param newTagName name of the tag to replace with
|
* @param newTagName name of the tag to replace with
|
||||||
|
* @param comment the comment for the tag use an empty string for no comment
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"# {0} - old tag name",
|
"# {0} - old tag name",
|
||||||
"# {1} - artifactID",
|
"# {1} - artifactID",
|
||||||
"ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}."})
|
"ReplaceBlackboardArtifactTagAction.replaceTag.alert=Unable to replace tag {0} for artifact {1}."})
|
||||||
@Override
|
@Override
|
||||||
protected void replaceTag( BlackboardArtifactTag oldArtifactTag, TagName newTagName) {
|
protected void replaceTag( BlackboardArtifactTag oldArtifactTag, TagName newTagName, String comment) {
|
||||||
new SwingWorker<Void, Void>() {
|
new SwingWorker<Void, Void>() {
|
||||||
|
|
||||||
@Override
|
@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
|
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldArtifactTag.getName().getDisplayName(), newTagName.getDisplayName(), oldArtifactTag.getContent().getName()}); //NON-NLS
|
||||||
|
|
||||||
tagsManager.deleteBlackboardArtifactTag(oldArtifactTag);
|
tagsManager.deleteBlackboardArtifactTag(oldArtifactTag);
|
||||||
tagsManager.addBlackboardArtifactTag(oldArtifactTag.getArtifact(), newTagName);
|
tagsManager.addBlackboardArtifactTag(oldArtifactTag.getArtifact(), newTagName, comment);
|
||||||
|
|
||||||
} catch (TskCoreException tskCoreException) {
|
} catch (TskCoreException tskCoreException) {
|
||||||
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
||||||
|
@ -64,7 +64,7 @@ public final class ReplaceContentTagAction extends ReplaceTagAction<ContentTag>
|
|||||||
"# {1} - content obj id",
|
"# {1} - content obj id",
|
||||||
"ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}."})
|
"ReplaceContentTagAction.replaceTag.alert=Unable to replace tag {0} for {1}."})
|
||||||
@Override
|
@Override
|
||||||
protected void replaceTag(ContentTag oldTag, TagName newTagName) {
|
protected void replaceTag(ContentTag oldTag, TagName newTagName, String comment) {
|
||||||
new SwingWorker<Void, Void>() {
|
new SwingWorker<Void, Void>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -84,7 +84,7 @@ public final class ReplaceContentTagAction extends ReplaceTagAction<ContentTag>
|
|||||||
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldTag.getName().getDisplayName(), newTagName.getDisplayName(), oldTag.getContent().getName()}); //NON-NLS
|
logger.log(Level.INFO, "Replacing tag {0} with tag {1} for artifact {2}", new Object[]{oldTag.getName().getDisplayName(), newTagName.getDisplayName(), oldTag.getContent().getName()}); //NON-NLS
|
||||||
|
|
||||||
tagsManager.deleteContentTag(oldTag);
|
tagsManager.deleteContentTag(oldTag);
|
||||||
tagsManager.addContentTag(oldTag.getContent(), newTagName);
|
tagsManager.addContentTag(oldTag.getContent(), newTagName, comment);
|
||||||
|
|
||||||
} catch (TskCoreException tskCoreException) {
|
} catch (TskCoreException tskCoreException) {
|
||||||
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
logger.log(Level.SEVERE, "Error replacing artifact tag", tskCoreException); //NON-NLS
|
||||||
|
@ -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
|
* Method to actually replace the selected tag with the given new tag
|
||||||
*
|
*
|
||||||
* @param oldTag
|
* @param oldTag - the TagName which is being removed from the item
|
||||||
* @param newTagName
|
* @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
|
* 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
|
// Add action to replace the tag
|
||||||
tagNameItem.addActionListener((ActionEvent event) -> {
|
tagNameItem.addActionListener((ActionEvent event) -> {
|
||||||
selectedTags.forEach((oldtag) -> {
|
selectedTags.forEach((oldtag) -> {
|
||||||
replaceTag(oldtag, entry.getValue());
|
replaceTag(oldtag, entry.getValue(), "");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -177,12 +178,24 @@ abstract class ReplaceTagAction<T extends Tag> extends AbstractAction implements
|
|||||||
TagName newTagName = GetTagNameDialog.doDialog();
|
TagName newTagName = GetTagNameDialog.doDialog();
|
||||||
if (null != newTagName) {
|
if (null != newTagName) {
|
||||||
selectedTags.forEach((oldtag) -> {
|
selectedTags.forEach((oldtag) -> {
|
||||||
replaceTag(oldtag, newTagName);
|
replaceTag(oldtag, newTagName, "");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
add(newTagMenuItem);
|
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.JPanel;
|
||||||
import javax.swing.JTextArea;
|
import javax.swing.JTextArea;
|
||||||
import javax.swing.JToggleButton;
|
import javax.swing.JToggleButton;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||||
@ -172,6 +173,9 @@ final class AddImageWizardSelectDspVisual extends JPanel {
|
|||||||
constraints.weighty = 1;
|
constraints.weighty = 1;
|
||||||
gridBagLayout.setConstraints(vertGlue, constraints);
|
gridBagLayout.setConstraints(vertGlue, constraints);
|
||||||
jPanel1.setLayout(gridBagLayout);
|
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.caseDetailsDialog.noCaseNameError=Error",
|
||||||
"DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."})
|
"DataContentViewerOtherCases.noOpenCase.errMsg=No open case available."})
|
||||||
private void showCaseDetails(int selectedRowViewIdx) {
|
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();
|
String caseDisplayName = Bundle.DataContentViewerOtherCases_caseDetailsDialog_noCaseNameError();
|
||||||
try {
|
try {
|
||||||
if (-1 != selectedRowViewIdx) {
|
if (-1 != selectedRowViewIdx) {
|
||||||
@ -225,7 +216,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
|||||||
}
|
}
|
||||||
caseDisplayName = eamCasePartial.getDisplayName();
|
caseDisplayName = eamCasePartial.getDisplayName();
|
||||||
// query case details
|
// query case details
|
||||||
CorrelationCase eamCase = dbManager.getCase(openCase);
|
CorrelationCase eamCase = dbManager.getCaseByUUID(eamCasePartial.getCaseUUID());
|
||||||
if (eamCase == null) {
|
if (eamCase == null) {
|
||||||
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
|
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
|
||||||
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
|
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
|
||||||
@ -246,6 +237,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
|||||||
DEFAULT_OPTION, PLAIN_MESSAGE);
|
DEFAULT_OPTION, PLAIN_MESSAGE);
|
||||||
}
|
}
|
||||||
} catch (EamDbException ex) {
|
} catch (EamDbException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error loading case details", ex);
|
||||||
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
|
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
|
||||||
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
|
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
|
||||||
caseDisplayName,
|
caseDisplayName,
|
||||||
|
@ -38,7 +38,7 @@ import java.util.logging.Level;
|
|||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil.updateSchemaVersion;
|
import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil.updateSchemaVersion;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
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.autopsy.healthmonitor.TimingMetric;
|
||||||
import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
|
import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
@ -881,7 +881,7 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
sql
|
sql
|
||||||
+= "+ (SELECT count(*) FROM "
|
+= "+ (SELECT count(*) FROM "
|
||||||
+ table_name
|
+ 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 {
|
try {
|
||||||
@ -1004,8 +1004,8 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
bulkArtifacts.get(type.getDbTableName()).clear();
|
bulkArtifacts.get(type.getDbTableName()).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingMetric timingMetric = EnterpriseHealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
|
TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
|
||||||
EnterpriseHealthMonitor.submitTimingMetric(timingMetric);
|
HealthMonitor.submitTimingMetric(timingMetric);
|
||||||
|
|
||||||
// Reset state
|
// Reset state
|
||||||
bulkArtifactsCount = 0;
|
bulkArtifactsCount = 0;
|
||||||
|
@ -49,7 +49,7 @@ import org.sleuthkit.datamodel.HashUtility;
|
|||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener;
|
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;
|
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,9 +135,9 @@ final class IngestModule implements FileIngestModule {
|
|||||||
*/
|
*/
|
||||||
if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) {
|
if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) {
|
||||||
try {
|
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);
|
List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
|
||||||
EnterpriseHealthMonitor.submitTimingMetric(timingMetric);
|
HealthMonitor.submitTimingMetric(timingMetric);
|
||||||
if (!caseDisplayNamesList.isEmpty()) {
|
if (!caseDisplayNamesList.isEmpty()) {
|
||||||
postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList);
|
postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList);
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,9 @@
|
|||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace min="0" pref="4" max="32767" attributes="0"/>
|
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||||
<Component id="showCasesPanel" min="-2" max="-2" attributes="0"/>
|
<Component id="showCasesPanel" pref="1188" max="32767" attributes="0"/>
|
||||||
<EmptySpace min="0" pref="4" max="32767" attributes="0"/>
|
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" alignment="1" attributes="0">
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
@ -43,9 +43,9 @@
|
|||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace min="0" pref="6" max="32767" attributes="0"/>
|
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||||
<Component id="showCasesPanel" min="-2" pref="426" max="-2" attributes="0"/>
|
<Component id="showCasesPanel" pref="473" max="32767" attributes="0"/>
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
|
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -63,7 +63,7 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="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">
|
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||||
<Component id="showCasesScrollPane" alignment="0" pref="527" max="32767" attributes="0"/>
|
<Component id="showCasesScrollPane" alignment="0" pref="527" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -71,7 +71,7 @@
|
|||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<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">
|
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||||
<Component id="showCasesScrollPane" alignment="0" pref="407" max="32767" attributes="0"/>
|
<Component id="showCasesScrollPane" alignment="0" pref="407" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -94,20 +94,17 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="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="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Component id="innerCaseScrollPane" alignment="0" pref="1423" max="32767" attributes="0"/>
|
||||||
<Component id="innerCaseScrollPane" min="-2" pref="1222" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<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">
|
<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>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
|
@ -107,17 +107,15 @@ final class ShowCasesDialog extends JDialog {
|
|||||||
outCasesPane.setLayout(outCasesPaneLayout);
|
outCasesPane.setLayout(outCasesPaneLayout);
|
||||||
outCasesPaneLayout.setHorizontalGroup(
|
outCasesPaneLayout.setHorizontalGroup(
|
||||||
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
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.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(outCasesPaneLayout.createSequentialGroup()
|
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1423, Short.MAX_VALUE))
|
||||||
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 1222, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(0, 0, Short.MAX_VALUE)))
|
|
||||||
);
|
);
|
||||||
outCasesPaneLayout.setVerticalGroup(
|
outCasesPaneLayout.setVerticalGroup(
|
||||||
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
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)
|
.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);
|
showCasesScrollPane.setViewportView(outCasesPane);
|
||||||
@ -126,13 +124,13 @@ final class ShowCasesDialog extends JDialog {
|
|||||||
showCasesPanel.setLayout(showCasesPanelLayout);
|
showCasesPanel.setLayout(showCasesPanelLayout);
|
||||||
showCasesPanelLayout.setHorizontalGroup(
|
showCasesPanelLayout.setHorizontalGroup(
|
||||||
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
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)
|
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 527, Short.MAX_VALUE))
|
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 527, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
showCasesPanelLayout.setVerticalGroup(
|
showCasesPanelLayout.setVerticalGroup(
|
||||||
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
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)
|
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 407, Short.MAX_VALUE))
|
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 407, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
@ -150,9 +148,9 @@ final class ShowCasesDialog extends JDialog {
|
|||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addGap(0, 4, Short.MAX_VALUE)
|
.addGap(6, 6, 6)
|
||||||
.addComponent(showCasesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1188, Short.MAX_VALUE)
|
||||||
.addGap(0, 4, Short.MAX_VALUE))
|
.addGap(6, 6, 6))
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addComponent(closeButton)
|
.addComponent(closeButton)
|
||||||
@ -161,9 +159,9 @@ final class ShowCasesDialog extends JDialog {
|
|||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addGap(0, 6, Short.MAX_VALUE)
|
.addGap(6, 6, 6)
|
||||||
.addComponent(showCasesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 426, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 473, Short.MAX_VALUE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(closeButton)
|
.addComponent(closeButton)
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
|
@ -20,13 +20,14 @@
|
|||||||
package org.sleuthkit.autopsy.commonfilesearch;
|
package org.sleuthkit.autopsy.commonfilesearch;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.sleuthkit.datamodel.TskData.FileKnown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides logic for selecting common files from all data sources.
|
* Provides logic for selecting common files from all data sources.
|
||||||
*/
|
*/
|
||||||
final public class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadataBuilder {
|
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
|
* 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.selectedFileCategoriesButton.toolTipText=Select from the options below...
|
||||||
CommonFilesPanel.pictureVideoCheckbox.text=Pictures and Videos
|
CommonFilesPanel.pictureVideoCheckbox.text=Pictures and Videos
|
||||||
CommonFilesPanel.documentsCheckbox.text=Documents
|
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.toolTipText=No filtering applied to results...
|
||||||
CommonFilesPanel.allFileCategoriesRadioButton.text=Match on all file types
|
CommonFilesPanel.allFileCategoriesRadioButton.text=Match on all file types
|
||||||
CommonFilesPanel.text=Indicate which data sources to consider while searching for duplicates:
|
CommonFilesPanel.text=Indicate which data sources to consider while searching for duplicates:
|
||||||
|
@ -104,12 +104,15 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
|
|||||||
CommonFilesPanel.this.selectDataSourceComboBox.setModel(CommonFilesPanel.this.dataSourcesList);
|
CommonFilesPanel.this.selectDataSourceComboBox.setModel(CommonFilesPanel.this.dataSourcesList);
|
||||||
|
|
||||||
boolean multipleDataSources = this.caseHasMultipleSources();
|
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) {
|
if (!multipleDataSources) {
|
||||||
CommonFilesPanel.this.withinDataSourceRadioButton.setSelected(true);
|
CommonFilesPanel.this.withinDataSourceRadioButton.setEnabled(false);
|
||||||
withinDataSourceSelected(true);
|
CommonFilesPanel.this.withinDataSourceRadioButton.setSelected(false);
|
||||||
|
withinDataSourceSelected(false);
|
||||||
|
CommonFilesPanel.this.selectDataSourceComboBox.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CommonFilesPanel.this.searchButton.setEnabled(true);
|
CommonFilesPanel.this.searchButton.setEnabled(true);
|
||||||
@ -120,7 +123,7 @@ public final class CommonFilesPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean caseHasMultipleSources() {
|
private boolean caseHasMultipleSources() {
|
||||||
return CommonFilesPanel.this.dataSourceMap.size() >= 2;
|
return CommonFilesPanel.this.dataSourceMap.size() >= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -19,11 +19,14 @@
|
|||||||
package org.sleuthkit.autopsy.commonfilesearch;
|
package org.sleuthkit.autopsy.commonfilesearch;
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.util.logging.Level;
|
||||||
import org.openide.util.HelpCtx;
|
import org.openide.util.HelpCtx;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.actions.CallableSystemAction;
|
import org.openide.util.actions.CallableSystemAction;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.core.Installer;
|
import org.sleuthkit.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.
|
* Encapsulates a menu action which triggers the common files search dialog.
|
||||||
@ -32,6 +35,7 @@ final public class CommonFilesSearchAction extends CallableSystemAction {
|
|||||||
|
|
||||||
private static CommonFilesSearchAction instance = null;
|
private static CommonFilesSearchAction instance = null;
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final Logger logger = Logger.getLogger(CommonFilesSearchAction.class.getName());
|
||||||
|
|
||||||
CommonFilesSearchAction() {
|
CommonFilesSearchAction() {
|
||||||
super();
|
super();
|
||||||
@ -40,7 +44,13 @@ final public class CommonFilesSearchAction extends CallableSystemAction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabled(){
|
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() {
|
public static synchronized CommonFilesSearchAction getDefault() {
|
||||||
|
@ -38,24 +38,27 @@ import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
|||||||
public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
||||||
|
|
||||||
private static final Map<String, Integer> COLUMN_WIDTHS;
|
private static final Map<String, Integer> COLUMN_WIDTHS;
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Map<String, Integer> map = new HashMap<>();
|
Map<String, Integer> map = new HashMap<>();
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_matchColLbl(), 235);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), 260);
|
||||||
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), 65);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), 300);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), 300);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), 200);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), 200);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), 100);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), 100);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), 150);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), 130);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_tagsColLbl1(), 300);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_tagsColLbl1(), 300);
|
||||||
|
|
||||||
COLUMN_WIDTHS = Collections.unmodifiableMap(map);
|
COLUMN_WIDTHS = Collections.unmodifiableMap(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"CommonFilesSearchResultsViewerTable.matchColLbl=Match",
|
"CommonFilesSearchResultsViewerTable.filesColLbl=Files",
|
||||||
|
"CommonFilesSearchResultsViewerTable.instancesColLbl=Instances",
|
||||||
"CommonFilesSearchResultsViewerTable.pathColLbl=Parent Path",
|
"CommonFilesSearchResultsViewerTable.pathColLbl=Parent Path",
|
||||||
"CommonFilesSearchResultsViewerTable.hashsetHitsColLbl=Hash Set Hits",
|
"CommonFilesSearchResultsViewerTable.hashsetHitsColLbl=Hash Set Hits",
|
||||||
"CommonFilesSearchResultsViewerTable.dataSourceColLbl=Data Source",
|
"CommonFilesSearchResultsViewerTable.dataSourceColLbl=Data Source(s)",
|
||||||
"CommonFilesSearchResultsViewerTable.mimeTypeColLbl=MIME Type",
|
"CommonFilesSearchResultsViewerTable.mimeTypeColLbl=MIME Type",
|
||||||
"CommonFilesSearchResultsViewerTable.tagsColLbl1=Tags"
|
"CommonFilesSearchResultsViewerTable.tagsColLbl1=Tags"
|
||||||
})
|
})
|
||||||
@ -68,7 +71,7 @@ public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
|||||||
|
|
||||||
TableColumn column = columnsEnumerator.nextElement();
|
TableColumn column = columnsEnumerator.nextElement();
|
||||||
|
|
||||||
final Object headerValue = column.getHeaderValue();
|
final String headerValue = column.getHeaderValue().toString();
|
||||||
final Integer get = COLUMN_WIDTHS.get(headerValue);
|
final Integer get = COLUMN_WIDTHS.get(headerValue);
|
||||||
|
|
||||||
column.setPreferredWidth(get);
|
column.setPreferredWidth(get);
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.commonfilesearch;
|
package org.sleuthkit.autopsy.commonfilesearch;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
@ -30,7 +28,7 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by the Common Files search feature to encapsulate instances of a given
|
* 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.
|
MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
|
||||||
*/
|
*/
|
||||||
public class FileInstanceNode extends FileNode {
|
public class FileInstanceNode extends FileNode {
|
||||||
|
|
||||||
@ -46,6 +44,8 @@ public class FileInstanceNode extends FileNode {
|
|||||||
public FileInstanceNode(AbstractFile fsContent, String dataSource) {
|
public FileInstanceNode(AbstractFile fsContent, String dataSource) {
|
||||||
super(fsContent);
|
super(fsContent);
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
|
|
||||||
|
this.setDisplayName(fsContent.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -73,64 +73,16 @@ public class FileInstanceNode extends FileNode {
|
|||||||
sheet.put(sheetSet);
|
sheet.put(sheetSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> map = new LinkedHashMap<>();
|
|
||||||
fillPropertyMap(map, this);
|
|
||||||
|
|
||||||
final String NO_DESCR = Bundle.FileInstanceNode_createSheet_noDescription();
|
final String NO_DESCR = Bundle.FileInstanceNode_createSheet_noDescription();
|
||||||
for (CommonFilePropertyType propType : CommonFilePropertyType.values()) {
|
|
||||||
final String propString = propType.toString();
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
|
||||||
final Object property = map.get(propString);
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
|
||||||
final NodeProperty<Object> nodeProperty = new NodeProperty<>(propString, propString, NO_DESCR, property);
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsForFile(this.getContent())));
|
||||||
sheetSet.put(nodeProperty);
|
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);
|
this.addTagProperty(sheetSet);
|
||||||
|
|
||||||
return sheet;
|
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.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.getContent().getMIMEType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates the columns to be displayed for reach row represented by an
|
|
||||||
* instance of this object.
|
|
||||||
*/
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"CommonFilePropertyType.pathColLbl=Parent Path",
|
|
||||||
"CommonFilePropertyType.hashsetHitsColLbl=Hash Set Hits",
|
|
||||||
"CommonFilePropertyType.dataSourceColLbl=Data Source",
|
|
||||||
"CommonFilePropertyType.caseColLbl=Case",
|
|
||||||
"CommonFilePropertyType.mimeTypeColLbl=MIME Type"
|
|
||||||
})
|
|
||||||
public enum CommonFilePropertyType {
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ package org.sleuthkit.autopsy.commonfilesearch;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
@ -50,7 +49,7 @@ final public class InstanceCountNode extends DisplayableItemNode {
|
|||||||
* @param md5Metadata
|
* @param md5Metadata
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"InstanceCountNode.displayName=Matches with %s instances"
|
"InstanceCountNode.displayName=Files with %s instances (%s)"
|
||||||
})
|
})
|
||||||
public InstanceCountNode(int instanceCount, List<Md5Metadata> md5Metadata) {
|
public InstanceCountNode(int instanceCount, List<Md5Metadata> md5Metadata) {
|
||||||
super(Children.create(new Md5NodeFactory(md5Metadata), true));
|
super(Children.create(new Md5NodeFactory(md5Metadata), true));
|
||||||
@ -58,7 +57,8 @@ final public class InstanceCountNode extends DisplayableItemNode {
|
|||||||
this.instanceCount = instanceCount;
|
this.instanceCount = instanceCount;
|
||||||
this.metadataList = md5Metadata;
|
this.metadataList = md5Metadata;
|
||||||
|
|
||||||
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount)));
|
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), md5Metadata.size()));
|
||||||
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,50 +102,12 @@ final public class InstanceCountNode extends DisplayableItemNode {
|
|||||||
sheet.put(sheetSet);
|
sheet.put(sheetSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> map = new LinkedHashMap<>();
|
|
||||||
fillPropertyMap(map, this);
|
|
||||||
|
|
||||||
final String NO_DESCR = Bundle.InstanceCountNode_createSheet_noDescription();
|
final String NO_DESCR = Bundle.InstanceCountNode_createSheet_noDescription();
|
||||||
for (InstanceCountNode.InstanceCountNodePropertyType propType : InstanceCountNode.InstanceCountNodePropertyType.values()) {
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, ""));
|
||||||
final String propString = propType.toString();
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), NO_DESCR, this.getInstanceCount()));
|
||||||
sheetSet.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sheet;
|
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, InstanceCountNode node) {
|
|
||||||
map.put(InstanceCountNodePropertyType.Match.toString(), node.getInstanceCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fields which will appear in the tree table.
|
|
||||||
*/
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"InstanceCountNodePropertyType.matchCountColLbl1=Match"
|
|
||||||
})
|
|
||||||
public enum InstanceCountNodePropertyType{
|
|
||||||
|
|
||||||
Match(Bundle.InstanceCountNodePropertyType_matchCountColLbl1());
|
|
||||||
|
|
||||||
final private String displayString;
|
|
||||||
|
|
||||||
private InstanceCountNodePropertyType(String displayName){
|
|
||||||
this.displayString = displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
return this.displayString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ChildFactory which builds CommonFileParentNodes from the
|
* ChildFactory which builds CommonFileParentNodes from the
|
||||||
|
@ -19,9 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.commonfilesearch;
|
package org.sleuthkit.autopsy.commonfilesearch;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
@ -52,6 +50,9 @@ public class Md5Node extends DisplayableItemNode {
|
|||||||
private final int commonFileCount;
|
private final int commonFileCount;
|
||||||
private final String dataSources;
|
private final String dataSources;
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"Md5Node.Md5Node.format=MD5: %s"
|
||||||
|
})
|
||||||
/**
|
/**
|
||||||
* Create a Match node whose children will all have this object in common.
|
* Create a Match node whose children will all have this object in common.
|
||||||
* @param data the common feature, and the children
|
* @param data the common feature, and the children
|
||||||
@ -64,7 +65,8 @@ public class Md5Node extends DisplayableItemNode {
|
|||||||
this.dataSources = String.join(", ", data.getDataSources());
|
this.dataSources = String.join(", ", data.getDataSources());
|
||||||
this.md5Hash = data.getMd5();
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,29 +103,15 @@ public class Md5Node extends DisplayableItemNode {
|
|||||||
sheet.put(sheetSet);
|
sheet.put(sheetSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> map = new LinkedHashMap<>();
|
|
||||||
fillPropertyMap(map, this);
|
|
||||||
|
|
||||||
final String NO_DESCR = Bundle.Md5Node_createSheet_noDescription();
|
final String NO_DESCR = Bundle.Md5Node_createSheet_noDescription();
|
||||||
for (Md5Node.CommonFileParentPropertyType propType : Md5Node.CommonFileParentPropertyType.values()) {
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, ""));
|
||||||
final String propString = propType.toString();
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, ""));
|
||||||
sheetSet.put(new NodeProperty<>(propString, propString, NO_DESCR, map.get(propString)));
|
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;
|
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.Case.toString(), "");
|
|
||||||
map.put(CommonFileParentPropertyType.DataSource.toString(), node.getDataSources());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||||
@ -172,24 +160,4 @@ public class Md5Node extends DisplayableItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"CommonFileParentPropertyType.fileColLbl=File",
|
|
||||||
"CommonFileParentPropertyType.instanceColLbl=Instance Count",
|
|
||||||
"CommonFileParentPropertyType.caseColLbl=Case",
|
|
||||||
"CommonFileParentPropertyType.dataSourceColLbl=Data Source"})
|
|
||||||
public enum CommonFileParentPropertyType {
|
|
||||||
|
|
||||||
DataSource(Bundle.CommonFileParentPropertyType_dataSourceColLbl());
|
|
||||||
|
|
||||||
final private String displayString;
|
|
||||||
|
|
||||||
private CommonFileParentPropertyType(String displayString) {
|
|
||||||
this.displayString = displayString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return this.displayString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -20,13 +20,14 @@
|
|||||||
package org.sleuthkit.autopsy.commonfilesearch;
|
package org.sleuthkit.autopsy.commonfilesearch;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.sleuthkit.datamodel.TskData.FileKnown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides logic for selecting common files from a single data source.
|
* Provides logic for selecting common files from a single data source.
|
||||||
*/
|
*/
|
||||||
final public class SingleDataSource extends CommonFilesMetadataBuilder {
|
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 Long selectedDataSourceId;
|
||||||
private final String dataSourceName;
|
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_HASHSET_HIT.getTypeID())
|
||||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())
|
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())
|
||||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_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;
|
return 3;
|
||||||
} else {
|
} else {
|
||||||
return 6;
|
return 6;
|
||||||
|
@ -28,7 +28,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
|||||||
* but the initial method was needed only be viewers in
|
* but the initial method was needed only be viewers in
|
||||||
* corecomponents and therefore can stay out of public API.
|
* corecomponents and therefore can stay out of public API.
|
||||||
*/
|
*/
|
||||||
class DataContentViewerUtility {
|
public class DataContentViewerUtility {
|
||||||
/**
|
/**
|
||||||
* Returns the first non-Blackboard Artifact from a Node.
|
* Returns the first non-Blackboard Artifact from a Node.
|
||||||
* Needed for (at least) Hex and Strings that want to view
|
* Needed for (at least) Hex and Strings that want to view
|
||||||
@ -39,7 +39,7 @@ class DataContentViewerUtility {
|
|||||||
* @param node Node passed into content viewer
|
* @param node Node passed into content viewer
|
||||||
* @return highest priority content or null if there is no content
|
* @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;
|
Content bbContentSeen = null;
|
||||||
for (Content content : (node).getLookup().lookupAll(Content.class)) {
|
for (Content content : (node).getLookup().lookupAll(Content.class)) {
|
||||||
if (content instanceof BlackboardArtifact) {
|
if (content instanceof BlackboardArtifact) {
|
||||||
|
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 {
|
||||||
|
|
||||||
|
}
|
@ -124,9 +124,9 @@ public class ImageUtils {
|
|||||||
if (OpenCvLoader.isOpenCvLoaded()) {
|
if (OpenCvLoader.isOpenCvLoaded()) {
|
||||||
try {
|
try {
|
||||||
if (System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64")) { //NON-NLS
|
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 {
|
} else {
|
||||||
System.loadLibrary("opencv_ffmpeg2413"); //NON-NLS
|
System.loadLibrary("opencv_ffmpeg248"); //NON-NLS
|
||||||
}
|
}
|
||||||
tempFfmpegLoaded = true;
|
tempFfmpegLoaded = true;
|
||||||
} catch (UnsatisfiedLinkError e) {
|
} catch (UnsatisfiedLinkError e) {
|
||||||
|
@ -54,7 +54,6 @@ DataModelActionsFactory.srcFileInDir.text=View Source File in Directory
|
|||||||
DataModelActionsFactory.fileInDir.text=View File in Directory
|
DataModelActionsFactory.fileInDir.text=View File in Directory
|
||||||
DataModelActionsFactory.viewNewWin.text=View in New Window
|
DataModelActionsFactory.viewNewWin.text=View in New Window
|
||||||
DataModelActionsFactory.openExtViewer.text=Open in External Viewer
|
DataModelActionsFactory.openExtViewer.text=Open in External Viewer
|
||||||
DataModelActionsFactory.srfFileSameMD5.text=Search for files with the same MD5 hash
|
|
||||||
DataSourcesNode.name=Data Sources
|
DataSourcesNode.name=Data Sources
|
||||||
DataSourcesNode.group_by_datasource.name=Data Source Files
|
DataSourcesNode.group_by_datasource.name=Data Source Files
|
||||||
DataSourcesNode.createSheet.name.name=Name
|
DataSourcesNode.createSheet.name.name=Name
|
||||||
|
@ -55,7 +55,6 @@ DataModelActionsFactory.srcFileInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u
|
|||||||
DataModelActionsFactory.fileInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u5185\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u8868\u793a
|
DataModelActionsFactory.fileInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u5185\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u8868\u793a
|
||||||
DataModelActionsFactory.viewNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30a6\u306b\u8868\u793a
|
DataModelActionsFactory.viewNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30a6\u306b\u8868\u793a
|
||||||
DataModelActionsFactory.openExtViewer.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u306b\u8868\u793a
|
DataModelActionsFactory.openExtViewer.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u306b\u8868\u793a
|
||||||
DataModelActionsFactory.srfFileSameMD5.text=\u540c\u3058MD5\u30cf\u30c3\u30b7\u30e5\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22
|
|
||||||
DataSourcesNode.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
|
DataSourcesNode.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
|
||||||
DataSourcesNode.group_by_datasource.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb
|
DataSourcesNode.group_by_datasource.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb
|
||||||
DataSourcesNode.createSheet.name.name=\u540d\u524d
|
DataSourcesNode.createSheet.name.name=\u540d\u524d
|
||||||
|
@ -38,7 +38,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
|||||||
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
|
import org.sleuthkit.autopsy.datamodel.Reports.ReportNode;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
@ -76,8 +75,6 @@ public class DataModelActionsFactory {
|
|||||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.viewNewWin.text");
|
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.viewNewWin.text");
|
||||||
public static final String OPEN_IN_EXTERNAL_VIEWER = NbBundle
|
public static final String OPEN_IN_EXTERNAL_VIEWER = NbBundle
|
||||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.openExtViewer.text");
|
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.openExtViewer.text");
|
||||||
public static final String SEARCH_FOR_FILES_SAME_MD5 = NbBundle
|
|
||||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.srfFileSameMD5.text");
|
|
||||||
|
|
||||||
public static List<Action> getActions(File file, boolean isArtifactSource) {
|
public static List<Action> getActions(File file, boolean isArtifactSource) {
|
||||||
List<Action> actionsList = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
@ -88,7 +85,6 @@ public class DataModelActionsFactory {
|
|||||||
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, fileNode));
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -367,7 +363,6 @@ public class DataModelActionsFactory {
|
|||||||
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, tagNode));
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
@ -404,7 +399,6 @@ public class DataModelActionsFactory {
|
|||||||
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, tagNode));
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
|
@ -34,7 +34,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
||||||
@ -166,7 +165,6 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
actionsList.add(null); // Creates an item separator
|
actionsList.add(null); // Creates an item separator
|
||||||
|
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(Bundle.FileNode_getActions_searchFilesSameMD5_text(), this));
|
|
||||||
actionsList.add(null); // Creates an item separator
|
actionsList.add(null); // Creates an item separator
|
||||||
|
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
||||||
@ -107,8 +106,6 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
|||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
|
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction(
|
|
||||||
NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.searchFilesSameMd5.text"), this));
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
@ -401,10 +401,8 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
}
|
}
|
||||||
Content c = ban.getLookup().lookup(File.class);
|
Content c = ban.getLookup().lookup(File.class);
|
||||||
Node n = null;
|
Node n = null;
|
||||||
boolean md5Action = false;
|
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
n = new FileNode((AbstractFile) c);
|
n = new FileNode((AbstractFile) c);
|
||||||
md5Action = true;
|
|
||||||
} else if ((c = ban.getLookup().lookup(Directory.class)) != null) {
|
} else if ((c = ban.getLookup().lookup(Directory.class)) != null) {
|
||||||
n = new DirectoryNode((Directory) c);
|
n = new DirectoryNode((Directory) c);
|
||||||
} else if ((c = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
|
} else if ((c = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
|
||||||
@ -438,10 +436,6 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
|
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
if (md5Action) {
|
|
||||||
actionsList.add(new HashSearchAction(
|
|
||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.searchFilesSameMd5.text"), n));
|
|
||||||
}
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
|
@ -18,11 +18,10 @@
|
|||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="treeView" alignment="0" max="32767" attributes="0"/>
|
<Component id="treeView" alignment="0" max="32767" attributes="0"/>
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<Component id="backButton" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="backButton" min="-2" pref="23" max="-2" attributes="0"/>
|
<Component id="forwardButton" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
<EmptySpace pref="51" max="32767" attributes="0"/>
|
||||||
<Component id="forwardButton" min="-2" pref="23" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace pref="65" max="32767" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
|
<Component id="showRejectedCheckBox" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
|
<Component id="groupByDatasourceCheckBox" min="-2" max="-2" attributes="0"/>
|
||||||
@ -43,14 +42,14 @@
|
|||||||
</Group>
|
</Group>
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="1" attributes="0">
|
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||||
<Component id="forwardButton" min="-2" pref="26" max="-2" attributes="1"/>
|
<Component id="forwardButton" max="32767" attributes="1"/>
|
||||||
<Component id="backButton" min="-2" pref="26" max="-2" attributes="1"/>
|
<Component id="backButton" min="-2" max="-2" attributes="1"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<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"/>
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
@ -72,7 +71,7 @@
|
|||||||
<Component class="javax.swing.JButton" name="backButton">
|
<Component class="javax.swing.JButton" name="backButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
<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>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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}")"/>
|
<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="borderPainted" type="boolean" value="false"/>
|
||||||
<Property name="contentAreaFilled" 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">
|
<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>
|
||||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||||
<Insets value="[2, 0, 2, 0]"/>
|
<Insets value="[2, 0, 2, 0]"/>
|
||||||
@ -92,10 +91,10 @@
|
|||||||
<Dimension value="[5, 5]"/>
|
<Dimension value="[5, 5]"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[23, 23]"/>
|
<Dimension value="[32, 32]"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
<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>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
@ -105,7 +104,7 @@
|
|||||||
<Component class="javax.swing.JButton" name="forwardButton">
|
<Component class="javax.swing.JButton" name="forwardButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
<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>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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}")"/>
|
<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="borderPainted" type="boolean" value="false"/>
|
||||||
<Property name="contentAreaFilled" 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">
|
<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>
|
||||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||||
<Insets value="[2, 0, 2, 0]"/>
|
<Insets value="[2, 0, 2, 0]"/>
|
||||||
@ -125,10 +124,10 @@
|
|||||||
<Dimension value="[5, 5]"/>
|
<Dimension value="[5, 5]"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[23, 23]"/>
|
<Dimension value="[32, 32]"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="rolloverIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
<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>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
|
@ -184,32 +184,32 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
|
|
||||||
treeView.setBorder(null);
|
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
|
org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.backButton.text")); // NOI18N
|
||||||
backButton.setBorderPainted(false);
|
backButton.setBorderPainted(false);
|
||||||
backButton.setContentAreaFilled(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.setMargin(new java.awt.Insets(2, 0, 2, 0));
|
||||||
backButton.setMaximumSize(new java.awt.Dimension(55, 100));
|
backButton.setMaximumSize(new java.awt.Dimension(55, 100));
|
||||||
backButton.setMinimumSize(new java.awt.Dimension(5, 5));
|
backButton.setMinimumSize(new java.awt.Dimension(5, 5));
|
||||||
backButton.setPreferredSize(new java.awt.Dimension(23, 23));
|
backButton.setPreferredSize(new java.awt.Dimension(32, 32));
|
||||||
backButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_back_hover.png"))); // NOI18N
|
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() {
|
backButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
backButtonActionPerformed(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
|
org.openide.awt.Mnemonics.setLocalizedText(forwardButton, org.openide.util.NbBundle.getMessage(DirectoryTreeTopComponent.class, "DirectoryTreeTopComponent.forwardButton.text")); // NOI18N
|
||||||
forwardButton.setBorderPainted(false);
|
forwardButton.setBorderPainted(false);
|
||||||
forwardButton.setContentAreaFilled(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.setMargin(new java.awt.Insets(2, 0, 2, 0));
|
||||||
forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
|
forwardButton.setMaximumSize(new java.awt.Dimension(55, 100));
|
||||||
forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
|
forwardButton.setMinimumSize(new java.awt.Dimension(5, 5));
|
||||||
forwardButton.setPreferredSize(new java.awt.Dimension(23, 23));
|
forwardButton.setPreferredSize(new java.awt.Dimension(32, 32));
|
||||||
forwardButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/directorytree/btn_step_forward_hover.png"))); // NOI18N
|
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() {
|
forwardButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
forwardButtonActionPerformed(evt);
|
forwardButtonActionPerformed(evt);
|
||||||
@ -231,11 +231,10 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(treeView)
|
.addComponent(treeView)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addGap(0, 0, 0)
|
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 51, Short.MAX_VALUE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 65, Short.MAX_VALUE)
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(showRejectedCheckBox)
|
.addComponent(showRejectedCheckBox)
|
||||||
.addComponent(groupByDatasourceCheckBox))
|
.addComponent(groupByDatasourceCheckBox))
|
||||||
@ -252,11 +251,11 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
.addComponent(groupByDatasourceCheckBox))
|
.addComponent(groupByDatasourceCheckBox))
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||||
.addComponent(forwardButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(forwardButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
.addComponent(backButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.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))
|
.addGap(0, 0, 0))
|
||||||
);
|
);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </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() {
|
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.
|
// refresh all children of the root.
|
||||||
autopsyTreeChildrenFactory.refreshChildren();
|
autopsyTreeChildrenFactory.refreshChildren();
|
||||||
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2011 Basis Technology Corp.
|
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.sleuthkit.autopsy.directorytree;
|
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import org.openide.nodes.Node;
|
|
||||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbSearchAction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to lookup the interface and call the real action in HashDatabase. The
|
|
||||||
* real action, HashDbSearchAction, implements HashSearchProvider, and should be
|
|
||||||
* the only instance of it.
|
|
||||||
*
|
|
||||||
* //TODO: HashDBSearchAction needs a public constructor and a service
|
|
||||||
* registration annotation for the lookup technique to work
|
|
||||||
*/
|
|
||||||
@Immutable
|
|
||||||
public class HashSearchAction extends AbstractAction {
|
|
||||||
|
|
||||||
private final Node contentNode;
|
|
||||||
|
|
||||||
public HashSearchAction(String title, Node contentNode) {
|
|
||||||
super(title);
|
|
||||||
this.contentNode = contentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
//HashSearchProvider searcher = Lookup.getDefault().lookup(HashSearchProvider.class);
|
|
||||||
//TODO: HashDBSearchAction needs a public constructor and a service registration annotation for the above technique to work
|
|
||||||
HashDbSearchAction searcher = HashDbSearchAction.getDefault();
|
|
||||||
searcher.search(contentNode);
|
|
||||||
}
|
|
||||||
}
|
|
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 javax.swing.border.EmptyBorder;
|
||||||
import org.openide.DialogDisplayer;
|
import org.openide.DialogDisplayer;
|
||||||
import org.openide.NotifyDescriptor;
|
import org.openide.NotifyDescriptor;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.windows.TopComponent;
|
import org.openide.windows.TopComponent;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
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.corecomponents.TableFilterNode;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.EmptyNode;
|
||||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
@ -166,6 +168,7 @@ class FileSearchPanel extends javax.swing.JPanel {
|
|||||||
* Action when the "Search" button is pressed.
|
* Action when the "Search" button is pressed.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@NbBundle.Messages("FileSearchPanel.emptyNode.display.text=No results found.")
|
||||||
private void search() {
|
private void search() {
|
||||||
// change the cursor to "waiting cursor" for this operation
|
// change the cursor to "waiting cursor" for this operation
|
||||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
@ -192,9 +195,16 @@ class FileSearchPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SearchNode sn = new SearchNode(contentList);
|
SearchNode sn = new SearchNode(contentList);
|
||||||
final TopComponent searchResultWin = DataResultTopComponent.createInstance(title, pathText,
|
TableFilterNode tableFilterNode = new TableFilterNode(sn, true, sn.getName());
|
||||||
new TableFilterNode(sn, true, sn.getName()), contentList.size());
|
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
|
searchResultWin.requestActive(); // make it the active top component
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,34 +53,32 @@ import org.sleuthkit.datamodel.Image;
|
|||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for recording data on the health of the system.
|
* Class for recording data on the health of the system.
|
||||||
*
|
*
|
||||||
* For timing data:
|
* For timing data: Modules will call getTimingMetric() before the code to be
|
||||||
* Modules will call getTimingMetric() before the code to be timed to get a TimingMetric object
|
* timed to get a TimingMetric object Modules will call submitTimingMetric()
|
||||||
* Modules will call submitTimingMetric() with the obtained TimingMetric object to log it
|
* with the obtained TimingMetric object to log it
|
||||||
*/
|
*/
|
||||||
public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
public final class HealthMonitor implements PropertyChangeListener {
|
||||||
|
|
||||||
private final static Logger logger = Logger.getLogger(EnterpriseHealthMonitor.class.getName());
|
private final static Logger logger = Logger.getLogger(HealthMonitor.class.getName());
|
||||||
private final static String DATABASE_NAME = "EnterpriseHealthMonitor";
|
private final static String DATABASE_NAME = "HealthMonitor";
|
||||||
private final static long DATABASE_WRITE_INTERVAL = 60; // Minutes
|
private final static long DATABASE_WRITE_INTERVAL = 60; // Minutes
|
||||||
public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
|
private final static CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 1);
|
||||||
= new CaseDbSchemaVersionNumber(1, 1);
|
|
||||||
|
|
||||||
private static final AtomicBoolean isEnabled = new AtomicBoolean(false);
|
private final static AtomicBoolean isEnabled = new AtomicBoolean(false);
|
||||||
private static EnterpriseHealthMonitor instance;
|
private static HealthMonitor instance;
|
||||||
|
|
||||||
private ScheduledThreadPoolExecutor healthMonitorOutputTimer;
|
private ScheduledThreadPoolExecutor healthMonitorOutputTimer;
|
||||||
private final Map<String, TimingInfo> timingInfoMap;
|
private final Map<String, TimingInfo> timingInfoMap;
|
||||||
private final List<UserData> userInfoList;
|
private final List<UserData> userInfoList;
|
||||||
private static final int CONN_POOL_SIZE = 10;
|
private final static int CONN_POOL_SIZE = 10;
|
||||||
private BasicDataSource connectionPool = null;
|
private BasicDataSource connectionPool = null;
|
||||||
private CaseDbConnectionInfo connectionSettingsInUse = null;
|
private CaseDbConnectionInfo connectionSettingsInUse = null;
|
||||||
private String hostName;
|
private String hostName;
|
||||||
|
|
||||||
private EnterpriseHealthMonitor() throws HealthMonitorException {
|
private HealthMonitor() throws HealthMonitorException {
|
||||||
|
|
||||||
// Create the map to collect timing metrics. The map will exist regardless
|
// Create the map to collect timing metrics. The map will exist regardless
|
||||||
// of whether the monitor is enabled.
|
// of whether the monitor is enabled.
|
||||||
@ -107,22 +105,25 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the instance of the EnterpriseHealthMonitor
|
* Get the instance of the HealthMonitor
|
||||||
|
*
|
||||||
* @return the instance
|
* @return the instance
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
synchronized static EnterpriseHealthMonitor getInstance() throws HealthMonitorException {
|
synchronized static HealthMonitor getInstance() throws HealthMonitorException {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = new EnterpriseHealthMonitor();
|
instance = new HealthMonitor();
|
||||||
Case.addPropertyChangeListener(instance);
|
Case.addPropertyChangeListener(instance);
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate the health monitor.
|
* Activate the health monitor. Creates/initialized the database (if
|
||||||
* Creates/initialized the database (if needed), clears any existing metrics
|
* needed), clears any existing metrics out of the maps, and sets up the
|
||||||
* out of the maps, and sets up the timer for writing to the database.
|
* timer for writing to the database.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private synchronized void activateMonitorLocally() throws HealthMonitorException {
|
private synchronized void activateMonitorLocally() throws HealthMonitorException {
|
||||||
@ -187,14 +188,14 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
if (currentSchema.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
|
if (currentSchema.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
|
||||||
|
|
||||||
// Add the user_data table
|
// Add the user_data table
|
||||||
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("+
|
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("
|
||||||
"id SERIAL PRIMARY KEY," +
|
+ "id SERIAL PRIMARY KEY,"
|
||||||
"host text NOT NULL," +
|
+ "host text NOT NULL,"
|
||||||
"timestamp bigint NOT NULL," +
|
+ "timestamp bigint NOT NULL,"
|
||||||
"event_type int NOT NULL," +
|
+ "event_type int NOT NULL,"
|
||||||
"is_examiner boolean NOT NULL," +
|
+ "is_examiner boolean NOT NULL,"
|
||||||
"case_name text NOT NULL" +
|
+ "case_name text NOT NULL"
|
||||||
")");
|
+ ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the schema version
|
// Update the schema version
|
||||||
@ -220,10 +221,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deactivate the health monitor.
|
* Deactivate the health monitor. This should only be used when disabling
|
||||||
* This should only be used when disabling the monitor, not when Autopsy is closing.
|
* the monitor, not when Autopsy is closing. Clears out any metrics that
|
||||||
* Clears out any metrics that haven't been written, stops the database write timer,
|
* haven't been written, stops the database write timer, and shuts down the
|
||||||
* and shuts down the connection pool.
|
* connection pool.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private synchronized void deactivateMonitorLocally() throws HealthMonitorException {
|
private synchronized void deactivateMonitorLocally() throws HealthMonitorException {
|
||||||
@ -238,7 +240,8 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the ScheduledThreadPoolExecutor that will handle the database writes.
|
* Start the ScheduledThreadPoolExecutor that will handle the database
|
||||||
|
* writes.
|
||||||
*/
|
*/
|
||||||
private synchronized void startTimer() {
|
private synchronized void startTimer() {
|
||||||
// Make sure the previous executor (if it exists) has been stopped
|
// Make sure the previous executor (if it exists) has been stopped
|
||||||
@ -258,7 +261,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from the installer to set up the Health Monitor instance at startup.
|
* Called from the installer to set up the Health Monitor instance at
|
||||||
|
* startup.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
static synchronized void startUpIfEnabled() throws HealthMonitorException {
|
static synchronized void startUpIfEnabled() throws HealthMonitorException {
|
||||||
@ -266,8 +271,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the application is closing.
|
* Called when the application is closing. Create a log off event and write
|
||||||
* Create a log off event and write all existing metrics to the database
|
* all existing metrics to the database
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
static synchronized void shutdown() throws HealthMonitorException {
|
static synchronized void shutdown() throws HealthMonitorException {
|
||||||
@ -277,7 +283,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Enabled/disable the health monitor.
|
* Enabled/disable the health monitor.
|
||||||
|
*
|
||||||
* @param enabled true to enable the monitor, false to disable it
|
* @param enabled true to enable the monitor, false to disable it
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
static synchronized void setEnabled(boolean enabled) throws HealthMonitorException {
|
static synchronized void setEnabled(boolean enabled) throws HealthMonitorException {
|
||||||
@ -304,12 +312,13 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a metric that will measure the time to execute a section of code.
|
* Get a metric that will measure the time to execute a section of code.
|
||||||
* Call this before the section of code to be timed and then
|
* Call this before the section of code to be timed and then submit it
|
||||||
* submit it afterward using submitTimingMetric().
|
* afterward using submitTimingMetric(). This method is safe to call
|
||||||
* This method is safe to call regardless of whether the Enterprise Health
|
* regardless of whether the health monitor is enabled.
|
||||||
* Monitor is enabled.
|
*
|
||||||
* @param name A short but descriptive name describing the code being timed.
|
* @param name A short but descriptive name describing the code being timed.
|
||||||
* This name will appear in the UI.
|
* This name will appear in the UI.
|
||||||
|
*
|
||||||
* @return The TimingMetric object
|
* @return The TimingMetric object
|
||||||
*/
|
*/
|
||||||
public static TimingMetric getTimingMetric(String name) {
|
public static TimingMetric getTimingMetric(String name) {
|
||||||
@ -321,9 +330,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit the metric that was previously obtained through getTimingMetric().
|
* Submit the metric that was previously obtained through getTimingMetric().
|
||||||
* Call this immediately after the section of code being timed.
|
* Call this immediately after the section of code being timed. This method
|
||||||
* This method is safe to call regardless of whether the Enterprise Health
|
* is safe to call regardless of whether the health monitor is enabled.
|
||||||
* Monitor is enabled.
|
*
|
||||||
* @param metric The TimingMetric object obtained from getTimingMetric()
|
* @param metric The TimingMetric object obtained from getTimingMetric()
|
||||||
*/
|
*/
|
||||||
public static void submitTimingMetric(TimingMetric metric) {
|
public static void submitTimingMetric(TimingMetric metric) {
|
||||||
@ -340,12 +349,14 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit the metric that was previously obtained through getTimingMetric(),
|
* Submit the metric that was previously obtained through getTimingMetric(),
|
||||||
* incorporating a count that the time should be divided by.
|
* incorporating a count that the time should be divided by. Call this
|
||||||
* Call this immediately after the section of code being timed.
|
* immediately after the section of code being timed. This method is safe to
|
||||||
* This method is safe to call regardless of whether the Enterprise Health
|
* call regardless of whether the health monitor is enabled.
|
||||||
* Monitor is enabled.
|
*
|
||||||
* @param metric The TimingMetric object obtained from getTimingMetric()
|
* @param metric The TimingMetric object obtained from
|
||||||
* @param normalization The number to divide the time by (a zero here will be treated as a one)
|
* getTimingMetric()
|
||||||
|
* @param normalization The number to divide the time by (a zero here will
|
||||||
|
* be treated as a one)
|
||||||
*/
|
*/
|
||||||
public static void submitNormalizedTimingMetric(TimingMetric metric, long normalization) {
|
public static void submitNormalizedTimingMetric(TimingMetric metric, long normalization) {
|
||||||
if (isEnabled.get() && (metric != null)) {
|
if (isEnabled.get() && (metric != null)) {
|
||||||
@ -362,7 +373,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the timing metric data to the map.
|
* Add the timing metric data to the map.
|
||||||
* @param metric The metric to add. stopTiming() should already have been called.
|
*
|
||||||
|
* @param metric The metric to add. stopTiming() should already have been
|
||||||
|
* called.
|
||||||
*/
|
*/
|
||||||
private void addTimingMetric(TimingMetric metric) throws HealthMonitorException {
|
private void addTimingMetric(TimingMetric metric) throws HealthMonitorException {
|
||||||
|
|
||||||
@ -385,6 +398,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a user event to the list.
|
* Add a user event to the list.
|
||||||
|
*
|
||||||
* @param eventType
|
* @param eventType
|
||||||
*/
|
*/
|
||||||
private void addUserEvent(UserEvent eventType) {
|
private void addUserEvent(UserEvent eventType) {
|
||||||
@ -395,18 +409,18 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Time a database query.
|
* Time a database query. Database queries are hard to test in normal
|
||||||
* Database queries are hard to test in normal processing because the time
|
* processing because the time is so dependent on the size of the tables
|
||||||
* is so dependent on the size of the tables being queried. We use getImages here
|
* being queried. We use getImages here because every table it queries is
|
||||||
* because every table it queries is the same size (one entry for each image) so
|
* the same size (one entry for each image) so we a) know the size of the
|
||||||
* we a) know the size of the tables and b) can use that table size to do
|
* tables and b) can use that table size to do normalization.
|
||||||
* normalization.
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private void performDatabaseQuery() throws HealthMonitorException {
|
private void performDatabaseQuery() throws HealthMonitorException {
|
||||||
try {
|
try {
|
||||||
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
||||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Database: getImages query");
|
TimingMetric metric = HealthMonitor.getTimingMetric("Database: getImages query");
|
||||||
List<Image> images = skCase.getImages();
|
List<Image> images = skCase.getImages();
|
||||||
|
|
||||||
// Through testing we found that this normalization gives us fairly
|
// Through testing we found that this normalization gives us fairly
|
||||||
@ -422,7 +436,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
normalization += 7;
|
normalization += 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnterpriseHealthMonitor.submitNormalizedTimingMetric(metric, normalization);
|
HealthMonitor.submitNormalizedTimingMetric(metric, normalization);
|
||||||
} catch (NoCurrentCaseException ex) {
|
} catch (NoCurrentCaseException ex) {
|
||||||
// If there's no case open, we just can't do the metrics.
|
// If there's no case open, we just can't do the metrics.
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
@ -432,6 +446,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect metrics at a scheduled time.
|
* Collect metrics at a scheduled time.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private void gatherTimerBasedMetrics() throws HealthMonitorException {
|
private void gatherTimerBasedMetrics() throws HealthMonitorException {
|
||||||
@ -440,6 +455,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the collected metrics to the database.
|
* Write the collected metrics to the database.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private void writeCurrentStateToDatabase() throws HealthMonitorException {
|
private void writeCurrentStateToDatabase() throws HealthMonitorException {
|
||||||
@ -525,9 +541,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the health monitor database exists.
|
* Check whether the health monitor database exists. Does not check the
|
||||||
* Does not check the schema.
|
* schema.
|
||||||
|
*
|
||||||
* @return true if the database exists, false otherwise
|
* @return true if the database exists, false otherwise
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private boolean databaseExists() throws HealthMonitorException {
|
private boolean databaseExists() throws HealthMonitorException {
|
||||||
@ -556,6 +574,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new health monitor database.
|
* Create a new health monitor database.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private void createDatabase() throws HealthMonitorException {
|
private void createDatabase() throws HealthMonitorException {
|
||||||
@ -576,6 +595,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup a connection pool for db connections.
|
* Setup a connection pool for db connections.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private void setupConnectionPool() throws HealthMonitorException {
|
private void setupConnectionPool() throws HealthMonitorException {
|
||||||
@ -609,6 +629,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Shut down the connection pool
|
* Shut down the connection pool
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private void shutdownConnections() throws HealthMonitorException {
|
private void shutdownConnections() throws HealthMonitorException {
|
||||||
@ -625,9 +646,10 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a database connection.
|
* Get a database connection. Sets up the connection pool if needed.
|
||||||
* Sets up the connection pool if needed.
|
*
|
||||||
* @return The Connection object
|
* @return The Connection object
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private Connection connect() throws HealthMonitorException {
|
private Connection connect() throws HealthMonitorException {
|
||||||
@ -645,9 +667,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the database schema has been initialized.
|
* Test whether the database schema has been initialized. We do this by
|
||||||
* We do this by looking for the version number.
|
* looking for the version number.
|
||||||
|
*
|
||||||
* @return True if it has been initialized, false otherwise.
|
* @return True if it has been initialized, false otherwise.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private boolean databaseIsInitialized() throws HealthMonitorException {
|
private boolean databaseIsInitialized() throws HealthMonitorException {
|
||||||
@ -680,8 +704,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether the health monitor is locally enabled.
|
* Return whether the health monitor is locally enabled. This does not query
|
||||||
* This does not query the database.
|
* the database.
|
||||||
|
*
|
||||||
* @return true if it is enabled, false otherwise
|
* @return true if it is enabled, false otherwise
|
||||||
*/
|
*/
|
||||||
static boolean monitorIsEnabled() {
|
static boolean monitorIsEnabled() {
|
||||||
@ -689,8 +714,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether monitoring should be enabled from the monitor database
|
* Check whether monitoring should be enabled from the monitor database and
|
||||||
* and enable/disable as needed.
|
* enable/disable as needed.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
synchronized void updateFromGlobalEnabledStatus() throws HealthMonitorException {
|
synchronized void updateFromGlobalEnabledStatus() throws HealthMonitorException {
|
||||||
@ -747,9 +773,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the enabled status from the database.
|
* Read the enabled status from the database. Check that the health monitor
|
||||||
* Check that the health monitor database exists before calling this.
|
* database exists before calling this.
|
||||||
|
*
|
||||||
* @return true if the database is enabled, false otherwise
|
* @return true if the database is enabled, false otherwise
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private boolean getGlobalEnabledStatusFromDB() throws HealthMonitorException {
|
private boolean getGlobalEnabledStatusFromDB() throws HealthMonitorException {
|
||||||
@ -769,6 +797,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the global enabled status in the database.
|
* Set the global enabled status in the database.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private void setGlobalEnabledStatusInDB(boolean status) throws HealthMonitorException {
|
private void setGlobalEnabledStatusInDB(boolean status) throws HealthMonitorException {
|
||||||
@ -783,7 +812,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current schema version
|
* Get the current schema version
|
||||||
|
*
|
||||||
* @return the current schema version
|
* @return the current schema version
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private CaseDbSchemaVersionNumber getVersion() throws HealthMonitorException {
|
private CaseDbSchemaVersionNumber getVersion() throws HealthMonitorException {
|
||||||
@ -837,6 +868,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the database.
|
* Initialize the database.
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private void initializeDatabaseSchema() throws HealthMonitorException {
|
private void initializeDatabaseSchema() throws HealthMonitorException {
|
||||||
@ -848,32 +880,31 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
try (Statement statement = conn.createStatement()) {
|
try (Statement statement = conn.createStatement()) {
|
||||||
conn.setAutoCommit(false);
|
conn.setAutoCommit(false);
|
||||||
|
|
||||||
statement.execute("CREATE TABLE IF NOT EXISTS timing_data (" +
|
statement.execute("CREATE TABLE IF NOT EXISTS timing_data ("
|
||||||
"id SERIAL PRIMARY KEY," +
|
+ "id SERIAL PRIMARY KEY,"
|
||||||
"name text NOT NULL," +
|
+ "name text NOT NULL,"
|
||||||
"host text NOT NULL," +
|
+ "host text NOT NULL,"
|
||||||
"timestamp bigint NOT NULL," +
|
+ "timestamp bigint NOT NULL,"
|
||||||
"count bigint NOT NULL," +
|
+ "count bigint NOT NULL,"
|
||||||
"average double precision NOT NULL," +
|
+ "average double precision NOT NULL,"
|
||||||
"max double precision NOT NULL," +
|
+ "max double precision NOT NULL,"
|
||||||
"min double precision NOT NULL" +
|
+ "min double precision NOT NULL"
|
||||||
")");
|
+ ")");
|
||||||
|
|
||||||
statement.execute("CREATE TABLE IF NOT EXISTS db_info (" +
|
statement.execute("CREATE TABLE IF NOT EXISTS db_info ("
|
||||||
"id SERIAL PRIMARY KEY NOT NULL," +
|
+ "id SERIAL PRIMARY KEY NOT NULL,"
|
||||||
"name text NOT NULL," +
|
+ "name text NOT NULL,"
|
||||||
"value text NOT NULL" +
|
+ "value text NOT NULL"
|
||||||
")");
|
+ ")");
|
||||||
|
|
||||||
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("+
|
|
||||||
"id SERIAL PRIMARY KEY," +
|
|
||||||
"host text NOT NULL," +
|
|
||||||
"timestamp bigint NOT NULL," +
|
|
||||||
"event_type int NOT NULL," +
|
|
||||||
"is_examiner BOOLEAN NOT NULL," +
|
|
||||||
"case_name text NOT NULL" +
|
|
||||||
")");
|
|
||||||
|
|
||||||
|
statement.execute("CREATE TABLE IF NOT EXISTS user_data ("
|
||||||
|
+ "id SERIAL PRIMARY KEY,"
|
||||||
|
+ "host text NOT NULL,"
|
||||||
|
+ "timestamp bigint NOT NULL,"
|
||||||
|
+ "event_type int NOT NULL,"
|
||||||
|
+ "is_examiner BOOLEAN NOT NULL,"
|
||||||
|
+ "case_name text NOT NULL"
|
||||||
|
+ ")");
|
||||||
|
|
||||||
statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')");
|
statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')");
|
||||||
statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')");
|
statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')");
|
||||||
@ -897,8 +928,8 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The task called by the ScheduledThreadPoolExecutor to handle
|
* The task called by the ScheduledThreadPoolExecutor to handle the periodic
|
||||||
* the periodic database update
|
* database update
|
||||||
*/
|
*/
|
||||||
static final class PeriodicHealthMonitorTask implements Runnable {
|
static final class PeriodicHealthMonitorTask implements Runnable {
|
||||||
|
|
||||||
@ -909,11 +940,10 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform all periodic tasks:
|
* Perform all periodic tasks: - Check if monitoring has been enabled /
|
||||||
* - Check if monitoring has been enabled / disabled in the database
|
* disabled in the database - Gather any additional metrics - Write current
|
||||||
* - Gather any additional metrics
|
* metric data to the database Do not run this from a new thread if the
|
||||||
* - Write current metric data to the database
|
* case/application is closing.
|
||||||
* Do not run this from a new thread if the case/application is closing.
|
|
||||||
*/
|
*/
|
||||||
private static void recordMetrics() {
|
private static void recordMetrics() {
|
||||||
try {
|
try {
|
||||||
@ -946,9 +976,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debugging method to generate sample data for the database.
|
* Debugging method to generate sample data for the database. It will delete
|
||||||
* It will delete all current timing data and replace it with randomly generated values.
|
* all current timing data and replace it with randomly generated values. If
|
||||||
* If there is more than one node, the second node's times will trend upwards.
|
* there is more than one node, the second node's times will trend upwards.
|
||||||
*/
|
*/
|
||||||
void populateDatabaseWithSampleData(int nDays, int nNodes, boolean createVerificationData) throws HealthMonitorException {
|
void populateDatabaseWithSampleData(int nDays, int nNodes, boolean createVerificationData) throws HealthMonitorException {
|
||||||
|
|
||||||
@ -986,8 +1016,6 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add timing metrics to the database
|
// Add timing metrics to the database
|
||||||
String addTimingInfoSql = "INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
String addTimingInfoSql = "INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||||
try (PreparedStatement statement = conn.prepareStatement(addTimingInfoSql)) {
|
try (PreparedStatement statement = conn.prepareStatement(addTimingInfoSql)) {
|
||||||
@ -1062,7 +1090,6 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
aveTime = day * 1000000;
|
aveTime = day * 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
statement.setString(1, metricName);
|
statement.setString(1, metricName);
|
||||||
statement.setString(2, host);
|
statement.setString(2, host);
|
||||||
statement.setLong(3, timestamp);
|
statement.setLong(3, timestamp);
|
||||||
@ -1096,8 +1123,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get timing metrics currently stored in the database.
|
* Get timing metrics currently stored in the database.
|
||||||
|
*
|
||||||
* @param timeRange Maximum age for returned metrics (in milliseconds)
|
* @param timeRange Maximum age for returned metrics (in milliseconds)
|
||||||
|
*
|
||||||
* @return A map with metric name mapped to a list of data
|
* @return A map with metric name mapped to a list of data
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
Map<String, List<DatabaseTimingResult>> getTimingMetricsFromDatabase(long timeRange) throws HealthMonitorException {
|
Map<String, List<DatabaseTimingResult>> getTimingMetricsFromDatabase(long timeRange) throws HealthMonitorException {
|
||||||
@ -1156,8 +1186,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user metrics currently stored in the database.
|
* Get user metrics currently stored in the database.
|
||||||
|
*
|
||||||
* @param timeRange Maximum age for returned metrics (in milliseconds)
|
* @param timeRange Maximum age for returned metrics (in milliseconds)
|
||||||
|
*
|
||||||
* @return A list of user metrics
|
* @return A list of user metrics
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
List<UserData> getUserMetricsFromDatabase(long timeRange) throws HealthMonitorException {
|
List<UserData> getUserMetricsFromDatabase(long timeRange) throws HealthMonitorException {
|
||||||
@ -1196,9 +1229,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an exclusive lock for the health monitor database.
|
* Get an exclusive lock for the health monitor database. Acquire this
|
||||||
* Acquire this before creating, initializing, or updating the database schema.
|
* before creating, initializing, or updating the database schema.
|
||||||
|
*
|
||||||
* @return The lock
|
* @return The lock
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private CoordinationService.Lock getExclusiveDbLock() throws HealthMonitorException {
|
private CoordinationService.Lock getExclusiveDbLock() throws HealthMonitorException {
|
||||||
@ -1215,9 +1250,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an shared lock for the health monitor database.
|
* Get an shared lock for the health monitor database. Acquire this before
|
||||||
* Acquire this before database reads or writes.
|
* database reads or writes.
|
||||||
|
*
|
||||||
* @return The lock
|
* @return The lock
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
private CoordinationService.Lock getSharedDbLock() throws HealthMonitorException {
|
private CoordinationService.Lock getSharedDbLock() throws HealthMonitorException {
|
||||||
@ -1251,6 +1288,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the integer value of the event to store in the database.
|
* Get the integer value of the event to store in the database.
|
||||||
|
*
|
||||||
* @return value corresponding to the event
|
* @return value corresponding to the event
|
||||||
*/
|
*/
|
||||||
int getEventValue() {
|
int getEventValue() {
|
||||||
@ -1259,8 +1297,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the UserEvent from the value stored in the database
|
* Get the UserEvent from the value stored in the database
|
||||||
|
*
|
||||||
* @param value
|
* @param value
|
||||||
|
*
|
||||||
* @return the corresponding UserEvent object
|
* @return the corresponding UserEvent object
|
||||||
|
*
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
static UserEvent valueOf(int value) throws HealthMonitorException {
|
static UserEvent valueOf(int value) throws HealthMonitorException {
|
||||||
@ -1273,8 +1314,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether a case is considered to be open given this event
|
* Return whether a case is considered to be open given this event as
|
||||||
* as the last recorded event.
|
* the last recorded event.
|
||||||
|
*
|
||||||
* @return true if a case is open, false otherwise
|
* @return true if a case is open, false otherwise
|
||||||
*/
|
*/
|
||||||
boolean caseIsOpen() {
|
boolean caseIsOpen() {
|
||||||
@ -1284,6 +1326,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
/**
|
/**
|
||||||
* Return whether a user is considered to be logged in given this event
|
* Return whether a user is considered to be logged in given this event
|
||||||
* as the last recorded event.
|
* as the last recorded event.
|
||||||
|
*
|
||||||
* @return true if a the user is logged in, false otherwise
|
* @return true if a the user is logged in, false otherwise
|
||||||
*/
|
*/
|
||||||
boolean userIsLoggedIn() {
|
boolean userIsLoggedIn() {
|
||||||
@ -1294,11 +1337,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class holding user metric data.
|
* Class holding user metric data. Can be used for storing new events or
|
||||||
* Can be used for storing new events or retrieving
|
* retrieving events out of the database.
|
||||||
* events out of the database.
|
|
||||||
*/
|
*/
|
||||||
static class UserData {
|
static class UserData {
|
||||||
|
|
||||||
private final UserEvent eventType;
|
private final UserEvent eventType;
|
||||||
private long timestamp;
|
private long timestamp;
|
||||||
private final boolean isExaminer;
|
private final boolean isExaminer;
|
||||||
@ -1306,8 +1349,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
private String caseName;
|
private String caseName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new UserData object using the given event type
|
* Create a new UserData object using the given event type and the
|
||||||
* and the current settings.
|
* current settings.
|
||||||
|
*
|
||||||
* @param eventType The type of event being recorded
|
* @param eventType The type of event being recorded
|
||||||
*/
|
*/
|
||||||
private UserData(UserEvent eventType) {
|
private UserData(UserEvent eventType) {
|
||||||
@ -1327,7 +1371,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a UserData object from a database result set.
|
* Create a UserData object from a database result set.
|
||||||
|
*
|
||||||
* @param resultSet The result set containing the data
|
* @param resultSet The result set containing the data
|
||||||
|
*
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
* @throws HealthMonitorException
|
* @throws HealthMonitorException
|
||||||
*/
|
*/
|
||||||
@ -1342,7 +1388,9 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
/**
|
/**
|
||||||
* This should only be used to make a dummy object to use for timestamp
|
* This should only be used to make a dummy object to use for timestamp
|
||||||
* comparisons.
|
* comparisons.
|
||||||
|
*
|
||||||
* @param timestamp
|
* @param timestamp
|
||||||
|
*
|
||||||
* @return A UserData object with the given timestamp
|
* @return A UserData object with the given timestamp
|
||||||
*/
|
*/
|
||||||
static UserData createDummyUserData(long timestamp) {
|
static UserData createDummyUserData(long timestamp) {
|
||||||
@ -1353,6 +1401,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the timestamp for the event
|
* Get the timestamp for the event
|
||||||
|
*
|
||||||
* @return Timestamp in milliseconds
|
* @return Timestamp in milliseconds
|
||||||
*/
|
*/
|
||||||
long getTimestamp() {
|
long getTimestamp() {
|
||||||
@ -1361,6 +1410,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the host that created the metric
|
* Get the host that created the metric
|
||||||
|
*
|
||||||
* @return the host name
|
* @return the host name
|
||||||
*/
|
*/
|
||||||
String getHostname() {
|
String getHostname() {
|
||||||
@ -1369,6 +1419,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the type of event
|
* Get the type of event
|
||||||
|
*
|
||||||
* @return the event type
|
* @return the event type
|
||||||
*/
|
*/
|
||||||
UserEvent getEventType() {
|
UserEvent getEventType() {
|
||||||
@ -1377,6 +1428,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether this node is an examiner node or an auto ingest node
|
* Check whether this node is an examiner node or an auto ingest node
|
||||||
|
*
|
||||||
* @return true if it is an examiner node
|
* @return true if it is an examiner node
|
||||||
*/
|
*/
|
||||||
boolean isExaminerNode() {
|
boolean isExaminerNode() {
|
||||||
@ -1385,6 +1437,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of the case for this metric
|
* Get the name of the case for this metric
|
||||||
|
*
|
||||||
* @return the case name. Will be the empty string if no case was open.
|
* @return the case name. Will be the empty string if no case was open.
|
||||||
*/
|
*/
|
||||||
String getCaseName() {
|
String getCaseName() {
|
||||||
@ -1393,14 +1446,14 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal class for collecting timing metrics.
|
* Internal class for collecting timing metrics. Instead of storing each
|
||||||
* Instead of storing each TimingMetric, we only store the min and max
|
* TimingMetric, we only store the min and max seen and the number of
|
||||||
* seen and the number of metrics and total duration to compute the average
|
* metrics and total duration to compute the average later. One TimingInfo
|
||||||
* later.
|
* instance should be created per metric name, and additional timing metrics
|
||||||
* One TimingInfo instance should be created per metric name, and
|
* will be added to it.
|
||||||
* additional timing metrics will be added to it.
|
|
||||||
*/
|
*/
|
||||||
private class TimingInfo {
|
private class TimingInfo {
|
||||||
|
|
||||||
private long count; // Number of metrics collected
|
private long count; // Number of metrics collected
|
||||||
private double sum; // Sum of the durations collected (nanoseconds)
|
private double sum; // Sum of the durations collected (nanoseconds)
|
||||||
private double max; // Maximum value found (nanoseconds)
|
private double max; // Maximum value found (nanoseconds)
|
||||||
@ -1414,11 +1467,14 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new TimingMetric to an existing TimingInfo object.
|
* Add a new TimingMetric to an existing TimingInfo object. This is
|
||||||
* This is called in a synchronized block for almost all new
|
* called in a synchronized block for almost all new TimingMetric
|
||||||
* TimingMetric objects, so do as little processing here as possible.
|
* objects, so do as little processing here as possible.
|
||||||
|
*
|
||||||
* @param metric The new metric
|
* @param metric The new metric
|
||||||
* @throws HealthMonitorException Will be thrown if the metric hasn't been stopped
|
*
|
||||||
|
* @throws HealthMonitorException Will be thrown if the metric hasn't
|
||||||
|
* been stopped
|
||||||
*/
|
*/
|
||||||
void addMetric(TimingMetric metric) throws HealthMonitorException {
|
void addMetric(TimingMetric metric) throws HealthMonitorException {
|
||||||
|
|
||||||
@ -1439,6 +1495,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the average duration
|
* Get the average duration
|
||||||
|
*
|
||||||
* @return average duration (milliseconds)
|
* @return average duration (milliseconds)
|
||||||
*/
|
*/
|
||||||
double getAverage() {
|
double getAverage() {
|
||||||
@ -1447,6 +1504,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maximum duration
|
* Get the maximum duration
|
||||||
|
*
|
||||||
* @return maximum duration (milliseconds)
|
* @return maximum duration (milliseconds)
|
||||||
*/
|
*/
|
||||||
double getMax() {
|
double getMax() {
|
||||||
@ -1455,6 +1513,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the minimum duration
|
* Get the minimum duration
|
||||||
|
*
|
||||||
* @return minimum duration (milliseconds)
|
* @return minimum duration (milliseconds)
|
||||||
*/
|
*/
|
||||||
double getMin() {
|
double getMin() {
|
||||||
@ -1463,6 +1522,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the total number of metrics collected
|
* Get the total number of metrics collected
|
||||||
|
*
|
||||||
* @return number of metrics collected
|
* @return number of metrics collected
|
||||||
*/
|
*/
|
||||||
long getCount() {
|
long getCount() {
|
||||||
@ -1471,10 +1531,11 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for retrieving timing metrics from the database to display to the user.
|
* Class for retrieving timing metrics from the database to display to the
|
||||||
* All times will be in milliseconds.
|
* user. All times will be in milliseconds.
|
||||||
*/
|
*/
|
||||||
static class DatabaseTimingResult {
|
static class DatabaseTimingResult {
|
||||||
|
|
||||||
private final long timestamp; // Time the metric was recorded
|
private final long timestamp; // Time the metric was recorded
|
||||||
private final String hostname; // Host that recorded the metric
|
private final String hostname; // Host that recorded the metric
|
||||||
private final long count; // Number of metrics collected
|
private final long count; // Number of metrics collected
|
||||||
@ -1493,6 +1554,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the timestamp for when the metric was recorded
|
* Get the timestamp for when the metric was recorded
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
long getTimestamp() {
|
long getTimestamp() {
|
||||||
@ -1501,6 +1563,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the average duration
|
* Get the average duration
|
||||||
|
*
|
||||||
* @return average duration (milliseconds)
|
* @return average duration (milliseconds)
|
||||||
*/
|
*/
|
||||||
double getAverage() {
|
double getAverage() {
|
||||||
@ -1509,6 +1572,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maximum duration
|
* Get the maximum duration
|
||||||
|
*
|
||||||
* @return maximum duration (milliseconds)
|
* @return maximum duration (milliseconds)
|
||||||
*/
|
*/
|
||||||
double getMax() {
|
double getMax() {
|
||||||
@ -1517,6 +1581,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the minimum duration
|
* Get the minimum duration
|
||||||
|
*
|
||||||
* @return minimum duration (milliseconds)
|
* @return minimum duration (milliseconds)
|
||||||
*/
|
*/
|
||||||
double getMin() {
|
double getMin() {
|
||||||
@ -1525,6 +1590,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the total number of metrics collected
|
* Get the total number of metrics collected
|
||||||
|
*
|
||||||
* @return number of metrics collected
|
* @return number of metrics collected
|
||||||
*/
|
*/
|
||||||
long getCount() {
|
long getCount() {
|
||||||
@ -1533,6 +1599,7 @@ public final class EnterpriseHealthMonitor implements PropertyChangeListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of the host that recorded this metric
|
* Get the name of the host that recorded this metric
|
||||||
|
*
|
||||||
* @return the host
|
* @return the host
|
||||||
*/
|
*/
|
||||||
String getHostName() {
|
String getHostName() {
|
@ -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_NAME = "adminAccess"; // NON-NLS
|
||||||
private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(Places.getUserDirectory().getAbsolutePath(), ADMIN_ACCESS_FILE_NAME).toString();
|
private final static String ADMIN_ACCESS_FILE_PATH = Paths.get(Places.getUserDirectory().getAbsolutePath(), ADMIN_ACCESS_FILE_NAME).toString();
|
||||||
|
|
||||||
Map<String, List<EnterpriseHealthMonitor.DatabaseTimingResult>> timingData;
|
Map<String, List<HealthMonitor.DatabaseTimingResult>> timingData;
|
||||||
List<EnterpriseHealthMonitor.UserData> userData;
|
List<HealthMonitor.UserData> userData;
|
||||||
|
|
||||||
private JComboBox<String> timingDateComboBox = null;
|
private JComboBox<String> timingDateComboBox = null;
|
||||||
private JComboBox<String> timingHostComboBox = null;
|
private JComboBox<String> timingHostComboBox = null;
|
||||||
@ -90,7 +90,7 @@ public class HealthMonitorDashboard {
|
|||||||
* Display the dashboard.
|
* Display the dashboard.
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({"HealthMonitorDashboard.display.errorCreatingDashboard=Error creating health monitor 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() {
|
public void display() {
|
||||||
|
|
||||||
// Update the enabled status and get the timing data, then create all
|
// Update the enabled status and get the timing data, then create all
|
||||||
@ -153,14 +153,14 @@ public class HealthMonitorDashboard {
|
|||||||
private void updateData() throws HealthMonitorException {
|
private void updateData() throws HealthMonitorException {
|
||||||
|
|
||||||
// Update the monitor status
|
// 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
|
// 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
|
// 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 {
|
private JPanel createTimingPanel() throws HealthMonitorException {
|
||||||
|
|
||||||
// If the monitor isn't enabled, just add a message
|
// If the monitor isn't enabled, just add a message
|
||||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
if(! HealthMonitor.monitorIsEnabled()) {
|
||||||
//timingMetricPanel.setPreferredSize(new Dimension(400,100));
|
//timingMetricPanel.setPreferredSize(new Dimension(400,100));
|
||||||
JPanel emptyTimingMetricPanel = new JPanel();
|
JPanel emptyTimingMetricPanel = new JPanel();
|
||||||
emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle()));
|
emptyTimingMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createTimingPanel_timingMetricsTitle()));
|
||||||
@ -223,7 +223,7 @@ public class HealthMonitorDashboard {
|
|||||||
JPanel timingControlPanel = new JPanel();
|
JPanel timingControlPanel = new JPanel();
|
||||||
|
|
||||||
// If the monitor is not enabled, don't add any components
|
// If the monitor is not enabled, don't add any components
|
||||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
if(! HealthMonitor.monitorIsEnabled()) {
|
||||||
return timingControlPanel;
|
return timingControlPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ public class HealthMonitorDashboard {
|
|||||||
// Create an array of host names
|
// Create an array of host names
|
||||||
Set<String> hostNameSet = new HashSet<>();
|
Set<String> hostNameSet = new HashSet<>();
|
||||||
for(String metricType:timingData.keySet()) {
|
for(String metricType:timingData.keySet()) {
|
||||||
for(EnterpriseHealthMonitor.DatabaseTimingResult result: timingData.get(metricType)) {
|
for(HealthMonitor.DatabaseTimingResult result: timingData.get(metricType)) {
|
||||||
hostNameSet.add(result.getHostName());
|
hostNameSet.add(result.getHostName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,7 +364,7 @@ public class HealthMonitorDashboard {
|
|||||||
for(String metricName:timingData.keySet()) {
|
for(String metricName:timingData.keySet()) {
|
||||||
|
|
||||||
// If necessary, trim down the list of results to fit the selected time range
|
// 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) {
|
if(timingDateComboBox.getSelectedItem() != null) {
|
||||||
DateRange selectedDateRange = DateRange.fromLabel(timingDateComboBox.getSelectedItem().toString());
|
DateRange selectedDateRange = DateRange.fromLabel(timingDateComboBox.getSelectedItem().toString());
|
||||||
long threshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
|
long threshold = System.currentTimeMillis() - selectedDateRange.getTimestampRange();
|
||||||
@ -403,7 +403,7 @@ public class HealthMonitorDashboard {
|
|||||||
"HealthMonitorDashboard.createUserPanel.userMetricsTitle=User Metrics"})
|
"HealthMonitorDashboard.createUserPanel.userMetricsTitle=User Metrics"})
|
||||||
private JPanel createUserPanel() throws HealthMonitorException {
|
private JPanel createUserPanel() throws HealthMonitorException {
|
||||||
// If the monitor isn't enabled, just add a message
|
// If the monitor isn't enabled, just add a message
|
||||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
if(! HealthMonitor.monitorIsEnabled()) {
|
||||||
JPanel emptyUserMetricPanel = new JPanel();
|
JPanel emptyUserMetricPanel = new JPanel();
|
||||||
emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle()));
|
emptyUserMetricPanel.add(new JLabel(Bundle.HealthMonitorDashboard_createUserPanel_userMetricsTitle()));
|
||||||
emptyUserMetricPanel.add(new JLabel(" "));
|
emptyUserMetricPanel.add(new JLabel(" "));
|
||||||
@ -448,7 +448,7 @@ public class HealthMonitorDashboard {
|
|||||||
JPanel userControlPanel = new JPanel();
|
JPanel userControlPanel = new JPanel();
|
||||||
|
|
||||||
// If the monitor is not enabled, don't add any components
|
// If the monitor is not enabled, don't add any components
|
||||||
if(! EnterpriseHealthMonitor.monitorIsEnabled()) {
|
if(! HealthMonitor.monitorIsEnabled()) {
|
||||||
return userControlPanel;
|
return userControlPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,7 +535,7 @@ public class HealthMonitorDashboard {
|
|||||||
JButton enableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_enableButton());
|
JButton enableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_enableButton());
|
||||||
JButton disableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_disableButton());
|
JButton disableButton = new JButton(Bundle.HealthMonitorDashboard_createAdminPanel_disableButton());
|
||||||
|
|
||||||
boolean isEnabled = EnterpriseHealthMonitor.monitorIsEnabled();
|
boolean isEnabled = HealthMonitor.monitorIsEnabled();
|
||||||
enableButton.setEnabled(! isEnabled);
|
enableButton.setEnabled(! isEnabled);
|
||||||
disableButton.setEnabled(isEnabled);
|
disableButton.setEnabled(isEnabled);
|
||||||
|
|
||||||
@ -545,7 +545,7 @@ public class HealthMonitorDashboard {
|
|||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
try {
|
try {
|
||||||
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
EnterpriseHealthMonitor.setEnabled(true);
|
HealthMonitor.setEnabled(true);
|
||||||
redisplay();
|
redisplay();
|
||||||
} catch (HealthMonitorException ex) {
|
} catch (HealthMonitorException ex) {
|
||||||
logger.log(Level.SEVERE, "Error enabling monitoring", ex);
|
logger.log(Level.SEVERE, "Error enabling monitoring", ex);
|
||||||
@ -561,7 +561,7 @@ public class HealthMonitorDashboard {
|
|||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
try {
|
try {
|
||||||
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
EnterpriseHealthMonitor.setEnabled(false);
|
HealthMonitor.setEnabled(false);
|
||||||
redisplay();
|
redisplay();
|
||||||
} catch (HealthMonitorException ex) {
|
} catch (HealthMonitorException ex) {
|
||||||
logger.log(Level.SEVERE, "Error disabling monitoring", ex);
|
logger.log(Level.SEVERE, "Error disabling monitoring", ex);
|
||||||
|
@ -45,7 +45,7 @@ public class Installer extends ModuleInstall {
|
|||||||
public void restored() {
|
public void restored() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
EnterpriseHealthMonitor.startUpIfEnabled();
|
HealthMonitor.startUpIfEnabled();
|
||||||
} catch (HealthMonitorException ex) {
|
} catch (HealthMonitorException ex) {
|
||||||
logger.log(Level.SEVERE, "Error starting health services monitor", ex);
|
logger.log(Level.SEVERE, "Error starting health services monitor", ex);
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ public class Installer extends ModuleInstall {
|
|||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
EnterpriseHealthMonitor.shutdown();
|
HealthMonitor.shutdown();
|
||||||
} catch (HealthMonitorException ex) {
|
} catch (HealthMonitorException ex) {
|
||||||
logger.log(Level.SEVERE, "Error stopping health services monitor", 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.TimeZone;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.openide.util.NbBundle;
|
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
|
* Creates a graph of the given timing metric data
|
||||||
|
@ -38,7 +38,7 @@ import javax.swing.JPanel;
|
|||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.openide.util.NbBundle;
|
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
|
* Creates graphs using the given user metric data
|
||||||
|
@ -95,7 +95,7 @@ public class FileTypeDetector {
|
|||||||
private static SortedSet<String> getTikaDetectedTypes() {
|
private static SortedSet<String> getTikaDetectedTypes() {
|
||||||
if (null == tikaDetectedTypes) {
|
if (null == tikaDetectedTypes) {
|
||||||
tikaDetectedTypes = org.apache.tika.mime.MimeTypes.getDefaultMimeTypes().getMediaTypeRegistry().getTypes()
|
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);
|
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.casemodule.services.Blackboard;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor;
|
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
|
||||||
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
|
||||||
import org.sleuthkit.autopsy.ingest.FileIngestModule;
|
import org.sleuthkit.autopsy.ingest.FileIngestModule;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||||
@ -184,7 +184,7 @@ public class HashDbIngestModule implements FileIngestModule {
|
|||||||
String md5Hash = file.getMd5Hash();
|
String md5Hash = file.getMd5Hash();
|
||||||
if (md5Hash == null || md5Hash.isEmpty()) {
|
if (md5Hash == null || md5Hash.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Disk Reads: Hash calculation");
|
TimingMetric metric = HealthMonitor.getTimingMetric("Disk Reads: Hash calculation");
|
||||||
long calcstart = System.currentTimeMillis();
|
long calcstart = System.currentTimeMillis();
|
||||||
md5Hash = HashUtility.calculateMd5Hash(file);
|
md5Hash = HashUtility.calculateMd5Hash(file);
|
||||||
if (file.getSize() > 0) {
|
if (file.getSize() > 0) {
|
||||||
@ -192,10 +192,10 @@ public class HashDbIngestModule implements FileIngestModule {
|
|||||||
// strongly with file size until the files get large.
|
// strongly with file size until the files get large.
|
||||||
// Only normalize if the file size is greater than ~1MB.
|
// Only normalize if the file size is greater than ~1MB.
|
||||||
if (file.getSize() < 1000000) {
|
if (file.getSize() < 1000000) {
|
||||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
HealthMonitor.submitTimingMetric(metric);
|
||||||
} else {
|
} else {
|
||||||
// In testing, this normalization gave reasonable resuls
|
// In testing, this normalization gave reasonable resuls
|
||||||
EnterpriseHealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000);
|
HealthMonitor.submitNormalizedTimingMetric(metric, file.getSize() / 500000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file.setMd5Hash(md5Hash);
|
file.setMd5Hash(md5Hash);
|
||||||
|
@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.MetaTypeCond
|
|||||||
*/
|
*/
|
||||||
public final class FilesSetsManager extends Observable {
|
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"})
|
"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_NAME_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", "/", ":", "*", "?", "\"", "<", ">")));
|
||||||
private static final List<String> ILLEGAL_FILE_PATH_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", ":", "*", "?", "\"", "<", ">")));
|
private static final List<String> ILLEGAL_FILE_PATH_CHARS = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("\\", ":", "*", "?", "\"", "<", ">")));
|
||||||
|
@ -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.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.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.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.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.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
|
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>
|
<binary-origin>release/modules/ext/jfxtras-common-8.0-r4.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/opencv-2413.jar</runtime-relative-path>
|
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/opencv-2413.jar</binary-origin>
|
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/jsr305-1.3.9.jar</runtime-relative-path>
|
<runtime-relative-path>ext/jsr305-1.3.9.jar</runtime-relative-path>
|
||||||
|
@ -380,6 +380,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
throw new AutoIngestMonitorException("Error removing priority for job " + job.toString(), ex);
|
throw new AutoIngestMonitorException("Error removing priority for job " + job.toString(), ex);
|
||||||
}
|
}
|
||||||
job.setPriority(DEFAULT_PRIORITY);
|
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);
|
throw new AutoIngestMonitorException("Error bumping priority for job " + job.toString(), ex);
|
||||||
}
|
}
|
||||||
job.setPriority(highestPriority);
|
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.
|
* priority.
|
||||||
*/
|
*/
|
||||||
if (null != jobToDeprioritize) {
|
if (null != jobToDeprioritize) {
|
||||||
@ -480,6 +490,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
}
|
}
|
||||||
jobToDeprioritize.setPriority(DEFAULT_PRIORITY);
|
jobToDeprioritize.setPriority(DEFAULT_PRIORITY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update job object in pending jobs queue
|
||||||
|
*/
|
||||||
|
jobsSnapshot.addOrReplacePendingJob(jobToDeprioritize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Publish a deprioritization event.
|
* Publish a deprioritization event.
|
||||||
*/
|
*/
|
||||||
@ -538,6 +553,11 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
}
|
}
|
||||||
jobToPrioritize.setPriority(highestPriority);
|
jobToPrioritize.setPriority(highestPriority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update job object in pending jobs queue
|
||||||
|
*/
|
||||||
|
jobsSnapshot.addOrReplacePendingJob(jobToPrioritize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Publish a prioritization event.
|
* Publish a prioritization event.
|
||||||
*/
|
*/
|
||||||
|
@ -102,6 +102,7 @@ public class SharedConfiguration {
|
|||||||
private boolean hideKnownFilesInViews;
|
private boolean hideKnownFilesInViews;
|
||||||
private boolean hideSlackFilesInDataSource;
|
private boolean hideSlackFilesInDataSource;
|
||||||
private boolean hideSlackFilesInViews;
|
private boolean hideSlackFilesInViews;
|
||||||
|
private boolean groupDatasources;
|
||||||
private boolean keepPreferredViewer;
|
private boolean keepPreferredViewer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -206,6 +207,8 @@ public class SharedConfiguration {
|
|||||||
uploadHashDbSettings(remoteFolder);
|
uploadHashDbSettings(remoteFolder);
|
||||||
uploadFileExporterSettings(remoteFolder);
|
uploadFileExporterSettings(remoteFolder);
|
||||||
uploadCentralRepositorySettings(remoteFolder);
|
uploadCentralRepositorySettings(remoteFolder);
|
||||||
|
uploadObjectDetectionClassifiers(remoteFolder);
|
||||||
|
uploadPythonModules(remoteFolder);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.deleteIfExists(uploadInProgress.toPath());
|
Files.deleteIfExists(uploadInProgress.toPath());
|
||||||
@ -271,6 +274,8 @@ public class SharedConfiguration {
|
|||||||
downloadAndroidTriageSettings(remoteFolder);
|
downloadAndroidTriageSettings(remoteFolder);
|
||||||
downloadFileExporterSettings(remoteFolder);
|
downloadFileExporterSettings(remoteFolder);
|
||||||
downloadCentralRepositorySettings(remoteFolder);
|
downloadCentralRepositorySettings(remoteFolder);
|
||||||
|
downloadObjectDetectionClassifiers(remoteFolder);
|
||||||
|
downloadPythonModules(remoteFolder);
|
||||||
|
|
||||||
// Download general settings, then restore the current
|
// Download general settings, then restore the current
|
||||||
// values for the unshared fields
|
// values for the unshared fields
|
||||||
@ -348,6 +353,7 @@ public class SharedConfiguration {
|
|||||||
fileIngestThreads = UserPreferences.numberOfFileIngestThreads();
|
fileIngestThreads = UserPreferences.numberOfFileIngestThreads();
|
||||||
hideSlackFilesInDataSource = UserPreferences.hideSlackFilesInDataSourcesTree();
|
hideSlackFilesInDataSource = UserPreferences.hideSlackFilesInDataSourcesTree();
|
||||||
hideSlackFilesInViews = UserPreferences.hideSlackFilesInViewsTree();
|
hideSlackFilesInViews = UserPreferences.hideSlackFilesInViewsTree();
|
||||||
|
groupDatasources = UserPreferences.groupItemsInTreeByDatasource();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -364,6 +370,7 @@ public class SharedConfiguration {
|
|||||||
UserPreferences.setNumberOfFileIngestThreads(fileIngestThreads);
|
UserPreferences.setNumberOfFileIngestThreads(fileIngestThreads);
|
||||||
UserPreferences.setHideSlackFilesInDataSourcesTree(hideSlackFilesInDataSource);
|
UserPreferences.setHideSlackFilesInDataSourcesTree(hideSlackFilesInDataSource);
|
||||||
UserPreferences.setHideSlackFilesInViewsTree(hideSlackFilesInViews);
|
UserPreferences.setHideSlackFilesInViewsTree(hideSlackFilesInViews);
|
||||||
|
UserPreferences.setGroupItemsInTreeByDatasource(groupDatasources);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -512,6 +519,71 @@ public class SharedConfiguration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* 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);
|
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
|
* Upload settings and hash databases to the shared folder. The general
|
||||||
* algorithm is: - Copy the general settings in hashsets.xml - For each hash
|
* algorithm is: - Copy the general settings in hashsets.xml - For each hash
|
||||||
|
@ -1179,6 +1179,12 @@ public final class DrawableDB {
|
|||||||
* @return the number of files with Cat-0
|
* @return the number of files with Cat-0
|
||||||
*/
|
*/
|
||||||
public long getUncategorizedCount(Collection<Long> fileIDs) {
|
public long getUncategorizedCount(Collection<Long> fileIDs) {
|
||||||
|
|
||||||
|
// if the fileset is empty, return count as 0
|
||||||
|
if (fileIDs.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
DrawableTagsManager tagsManager = controller.getTagsManager();
|
DrawableTagsManager tagsManager = controller.getTagsManager();
|
||||||
|
|
||||||
// get a comma seperated list of TagName ids for non zero categories
|
// get a comma seperated list of TagName ids for non zero categories
|
||||||
|
@ -82,6 +82,7 @@ import org.sleuthkit.datamodel.ContentTag;
|
|||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TagName;
|
import org.sleuthkit.datamodel.TagName;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.TskData.DbType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides an abstraction layer on top of {@link DrawableDB} ( and to some
|
* Provides an abstraction layer on top of {@link DrawableDB} ( and to some
|
||||||
@ -351,11 +352,22 @@ public class GroupManager {
|
|||||||
case MIME_TYPE:
|
case MIME_TYPE:
|
||||||
if (nonNull(db)) {
|
if (nonNull(db)) {
|
||||||
HashSet<String> types = new HashSet<>();
|
HashSet<String> types = new HashSet<>();
|
||||||
try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery("select group_concat(obj_id), mime_type from tsk_files group by mime_type "); //NON-NLS
|
|
||||||
|
// Use the group_concat function to get a list of files for each mime type.
|
||||||
|
// This has different syntax on Postgres vs SQLite
|
||||||
|
String groupConcatClause;
|
||||||
|
if (DbType.POSTGRESQL == controller.getSleuthKitCase().getDatabaseType()) {
|
||||||
|
groupConcatClause = " array_to_string(array_agg(obj_id), ',') as object_ids";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
groupConcatClause = " group_concat(obj_id) as object_ids";
|
||||||
|
}
|
||||||
|
String query = "select " + groupConcatClause + " , mime_type from tsk_files group by mime_type ";
|
||||||
|
try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery(query); //NON-NLS
|
||||||
ResultSet resultSet = executeQuery.getResultSet();) {
|
ResultSet resultSet = executeQuery.getResultSet();) {
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
final String mimeType = resultSet.getString("mime_type"); //NON-NLS
|
final String mimeType = resultSet.getString("mime_type"); //NON-NLS
|
||||||
String objIds = resultSet.getString("group_concat(obj_id)"); //NON-NLS
|
String objIds = resultSet.getString("object_ids"); //NON-NLS
|
||||||
|
|
||||||
Pattern.compile(",").splitAsStream(objIds)
|
Pattern.compile(",").splitAsStream(objIds)
|
||||||
.map(Long::valueOf)
|
.map(Long::valueOf)
|
||||||
|
@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
|||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
@ -48,7 +47,6 @@ import org.sleuthkit.datamodel.LayoutFile;
|
|||||||
import org.sleuthkit.datamodel.LocalFile;
|
import org.sleuthkit.datamodel.LocalFile;
|
||||||
import org.sleuthkit.datamodel.Report;
|
import org.sleuthkit.datamodel.Report;
|
||||||
import org.sleuthkit.datamodel.SlackFile;
|
import org.sleuthkit.datamodel.SlackFile;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
|
||||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,50 +124,45 @@ class AdHocSearchFilterNode extends FilterNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(File f) {
|
public List<Action> visit(File f) {
|
||||||
return getFileActions(true);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(DerivedFile f) {
|
public List<Action> visit(DerivedFile f) {
|
||||||
return getFileActions(true);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(Directory d) {
|
public List<Action> visit(Directory d) {
|
||||||
return getFileActions(false);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(LayoutFile lf) {
|
public List<Action> visit(LayoutFile lf) {
|
||||||
//we want hashsearch enabled on carved files but not unallocated blocks
|
return getFileActions();
|
||||||
boolean enableHashSearch = (lf.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.CARVED);
|
|
||||||
return getFileActions(enableHashSearch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(LocalFile lf) {
|
public List<Action> visit(LocalFile lf) {
|
||||||
return getFileActions(true);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(SlackFile f) {
|
public List<Action> visit(SlackFile f) {
|
||||||
return getFileActions(false);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Action> visit(VirtualDirectory dir) {
|
public List<Action> visit(VirtualDirectory dir) {
|
||||||
return getFileActions(false);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Action> getFileActions(boolean enableHashSearch) {
|
private List<Action> getFileActions() {
|
||||||
List<Action> actionsList = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), AdHocSearchFilterNode.this));
|
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), AdHocSearchFilterNode.this));
|
||||||
actionsList.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal()));
|
actionsList.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal()));
|
||||||
actionsList.add(null);
|
actionsList.add(null);
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
Action hashSearchAction = new HashSearchAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.searchSameMd5"), getOriginal());
|
|
||||||
hashSearchAction.setEnabled(enableHashSearch);
|
|
||||||
actionsList.add(hashSearchAction);
|
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
@ -185,7 +178,7 @@ class AdHocSearchFilterNode extends FilterNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Action> defaultVisit(Content c) {
|
protected List<Action> defaultVisit(Content c) {
|
||||||
return getFileActions(false);
|
return getFileActions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ import org.apache.solr.common.SolrInputDocument;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
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.healthmonitor.TimingMetric;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||||
import org.sleuthkit.autopsy.keywordsearch.Chunker.Chunk;
|
import org.sleuthkit.autopsy.keywordsearch.Chunker.Chunk;
|
||||||
@ -237,9 +237,9 @@ class Ingester {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
//TODO: consider timeout thread, or vary socket timeout based on size of indexed content
|
//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);
|
solrServer.addDocument(updateDoc);
|
||||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
HealthMonitor.submitTimingMetric(metric);
|
||||||
uncommitedIngests = true;
|
uncommitedIngests = true;
|
||||||
|
|
||||||
} catch (KeywordSearchModuleException | NoOpenCoreException ex) {
|
} 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.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
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.healthmonitor.TimingMetric;
|
||||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
|
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
@ -710,9 +710,9 @@ public class Server {
|
|||||||
if (null == currentCore) {
|
if (null == currentCore) {
|
||||||
throw new NoOpenCoreException();
|
throw new NoOpenCoreException();
|
||||||
}
|
}
|
||||||
TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Index chunk");
|
TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Index chunk");
|
||||||
currentCore.addDocument(doc);
|
currentCore.addDocument(doc);
|
||||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
HealthMonitor.submitTimingMetric(metric);
|
||||||
} finally {
|
} finally {
|
||||||
currentCoreLock.readLock().unlock();
|
currentCoreLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@ -781,9 +781,9 @@ public class Server {
|
|||||||
IndexingServerProperties properties = getMultiUserServerProperties(theCase.getCaseDirectory());
|
IndexingServerProperties properties = getMultiUserServerProperties(theCase.getCaseDirectory());
|
||||||
currentSolrServer = new HttpSolrServer("http://" + properties.getHost() + ":" + properties.getPort() + "/solr"); //NON-NLS
|
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);
|
connectToSolrServer(currentSolrServer);
|
||||||
EnterpriseHealthMonitor.submitTimingMetric(metric);
|
HealthMonitor.submitTimingMetric(metric);
|
||||||
|
|
||||||
} catch (SolrServerException | IOException ex) {
|
} catch (SolrServerException | IOException ex) {
|
||||||
throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg", ex.getLocalizedMessage()), ex);
|
throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg", ex.getLocalizedMessage()), ex);
|
||||||
@ -1325,13 +1325,13 @@ public class Server {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
void connectToSolrServer(HttpSolrServer solrServer) throws SolrServerException, 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();
|
CoreAdminRequest statusRequest = new CoreAdminRequest();
|
||||||
statusRequest.setCoreName( null );
|
statusRequest.setCoreName( null );
|
||||||
statusRequest.setAction( CoreAdminParams.CoreAdminAction.STATUS );
|
statusRequest.setAction( CoreAdminParams.CoreAdminAction.STATUS );
|
||||||
statusRequest.setIndexInfoNeeded(false);
|
statusRequest.setIndexInfoNeeded(false);
|
||||||
statusRequest.process(solrServer);
|
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 --------------
|
---------------- VERSION 4.7.0 --------------
|
||||||
New Features:
|
New Features:
|
||||||
- A graph visualization was added to the Communications tool to make it easier to find messages and relationships.
|
- 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
|
#Updated by build script
|
||||||
#Fri, 15 Jun 2018 12:30:02 -0600
|
#Mon, 25 Jun 2018 17:19:36 -0400
|
||||||
LBL_splash_window_title=Starting Autopsy
|
LBL_splash_window_title=Starting Autopsy
|
||||||
SPLASH_HEIGHT=314
|
SPLASH_HEIGHT=314
|
||||||
SPLASH_WIDTH=538
|
SPLASH_WIDTH=538
|
||||||
@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18
|
|||||||
SplashRunningTextColor=0x0
|
SplashRunningTextColor=0x0
|
||||||
SplashRunningTextFontSize=19
|
SplashRunningTextFontSize=19
|
||||||
|
|
||||||
currentVersion=Autopsy 4.7.0
|
currentVersion=Autopsy 4.8.0
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#Updated by build script
|
#Updated by build script
|
||||||
#Fri, 15 Jun 2018 12:30:02 -0600
|
#Mon, 25 Jun 2018 17:19:36 -0400
|
||||||
CTL_MainWindow_Title=Autopsy 4.7.0
|
CTL_MainWindow_Title=Autopsy 4.8.0
|
||||||
CTL_MainWindow_Title_No_Project=Autopsy 4.7.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
|
\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
|
\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.
|
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
|
\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
|
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.
|
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>
|
- <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>
|
- <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>
|
- <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).
|
- 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
|
\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
|
\image html central_repo_options.png
|
||||||
|
|
||||||
\subsection cr_db_setup Setting up the Database
|
\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>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.
|
- <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.
|
||||||
|
|
||||||
@ -90,6 +90,12 @@ One default org, "Not Specified" will always be present in the list. New organiz
|
|||||||
|
|
||||||
\image html central_repo_new_org.png
|
\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
|
\section cr_using_repo Using the Central Repository
|
||||||
|
|
||||||
\subsection cr_ingest_module Correlation Engine Module
|
\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
|
\subsection cr_tagging Tagging Files and Artifacts
|
||||||
|
|
||||||
Any file or artifact that a user tags with a tag with notable set will be added
|
Tagging a file or artifact with a "notable" tag will change its associated property in the central repository to notable as well.
|
||||||
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)
|
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.
|
||||||
will use those notable files or artifacts in a similar manner as a Known Bad hash set, causing matching files from that
|
Any future data source ingest (where this module is enabled)
|
||||||
ingest to be added to the Interesting Artifacts list in that currently open case.
|
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
|
\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
|
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.
|
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
|
\image html central_repo_disable_flagging.png
|
||||||
|
|
||||||
@ -125,9 +134,16 @@ Results from enabling a central repository and running the Correlation Engine In
|
|||||||
|
|
||||||
\subsection cr_content_viewer Content Viewer
|
\subsection cr_content_viewer Content Viewer
|
||||||
|
|
||||||
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 files and artifacts from other cases, 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 files and artifacts from the central repository. 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.
|
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.
|
||||||
|
|
||||||
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
|
\image html central_repo_content_viewer.png
|
||||||
|
|
||||||
@ -169,7 +185,7 @@ the Case -> Case Properties menu.
|
|||||||
|
|
||||||
<b>Show Frequency</b>
|
<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>
|
<b>Add/Edit Comment</b>
|
||||||
|
|
||||||
@ -179,15 +195,19 @@ This allows you to add a comment for this entry or edit an existing comment. If
|
|||||||
|
|
||||||
\subsection cr_interesting_items Interesting Items
|
\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
|
\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.
|
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
|
||||||
|
|
||||||
|
*/
|
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
|
||||||
|
|
||||||
|
*/
|
@ -1,5 +1,5 @@
|
|||||||
<hr/>
|
<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
|
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>.
|
<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>
|
</i></p>
|
||||||
|
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: 67 KiB After Width: | Height: | Size: 51 KiB |
BIN
docs/doxygen-user/images/experimental_plugins_menu.png
Normal file
After Width: | Height: | Size: 48 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 stix_page
|
||||||
- \subpage central_repo_page
|
- \subpage central_repo_page
|
||||||
- \subpage communications_page
|
- \subpage communications_page
|
||||||
|
- \subpage common_files_page
|
||||||
- \subpage logs_and_output_page
|
- \subpage logs_and_output_page
|
||||||
- Reporting
|
- Reporting
|
||||||
- \subpage tagging_page
|
- \subpage tagging_page
|
||||||
@ -63,6 +64,7 @@ The following topics are available here:
|
|||||||
- \subpage multiuser_page
|
- \subpage multiuser_page
|
||||||
- \subpage live_triage_page
|
- \subpage live_triage_page
|
||||||
- \subpage advanced_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.
|
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
|
\image html tagging-1.PNG
|
||||||
|
|
||||||
Once you have chosen to tag the file or the result, there are two more options:
|
At this point there are three options:
|
||||||
- Quick Tag -- use this if you just want the tag
|
- 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
|
- Tag and Comment -- use this if you need to add a comment about this tag
|
||||||
|
|
||||||
\image html tagging-2.PNG
|
\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>
|
<br>
|
||||||
There are several default tag names:
|
There are several default tag names:
|
||||||
- Bookmark - Default tag for marking files of interest
|
- 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
|
- 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
|
- 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".
|
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.
|
||||||
|
|
||||||
\image html tagging-3.PNG
|
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
/*! \page tree_viewer_page Tree Viewer
|
/*! \page tree_viewer_page Tree Viewer
|
||||||
|
|
||||||
The Tree Viewer shows the discovered folders by the data sources they come from, as well as a list of files in the folders. It is located on the left side of the Autopsy screen.
|
The Tree Viewer shows the discovered folders by the data sources they come from, as well as a list of files in the folders. It is located on the left side of the Autopsy screen. The "Group by Data Source" option on the top left moves all views, results, and tags under their corresponding data source.
|
||||||
|
|
||||||
Each folder in the tree on the left shows how many items are contained within it in parenthesis after the directory name. See the picture below.
|
Each folder in the tree on the left shows how many items are contained within it in parentheses after the directory name. See the picture below.
|
||||||
|
|
||||||
<br>
|
|
||||||
\image html directory-tree.PNG
|
\image html directory-tree.PNG
|
||||||
<br>
|
|
||||||
*/
|
*/
|
||||||
|
@ -21,12 +21,16 @@ The major areas in the Autopsy User Interface (UI) are:
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
||||||
The tree on the left-hand side is find saved results from automated procedures (ingest). The tree has four main areas:
|
The tree on the left-hand side is where you can browse the files in the image and find saved results from automated procedures (ingest). The tree has five main areas:
|
||||||
- <b>Data Sources:</b> This shows the directory tree hierarchy of the file systems in the images. You can navigate to a specific file or directory here. Each data source added is represented as a drive. If you add a data source multiple times, it shows up multiple times.
|
- <b>Data Sources:</b> This shows the directory tree hierarchy of the file systems in the images. You can navigate to a specific file or directory here. Each data source added is represented as a drive. If you add a data source multiple times, it shows up multiple times.
|
||||||
- <b>Views:</b> Specific types of files from the data sources are shown here, aggregated by type or other properties. Files here can come from more than one data source. Look here for files of a specific type or property.
|
- <b>Views:</b> Specific types of files from the data sources are shown here, aggregated by type or other properties. Files here can come from more than one data source. Look here for files of a specific type or property.
|
||||||
- <b>Results:</b> Where you can see the results from the background ingest tasks and you can see your previous search results. Go here to see what was found by the ingest modules and to find your previous search results.
|
- <b>Results:</b> Where you can see the results from the background ingest tasks and you can see your previous search results. Go here to see what was found by the ingest modules and to find your previous search results.
|
||||||
|
- <b>Tags:</b> Where files and results that have been \ref tagging_page "tagged" are shown
|
||||||
- <b>Reports:</b> References to reports that you have generated or that ingest modules have created show up here
|
- <b>Reports:</b> References to reports that you have generated or that ingest modules have created show up here
|
||||||
|
|
||||||
|
You can also use the "Group by Data Source" option at the upper left of the tree display to move the views, results, and tags subtrees under their corresponding data sources. This can be helpful on very large cases to reduce the size of each node.
|
||||||
|
|
||||||
|
\image html ui_layout_group_tree.PNG
|
||||||
|
|
||||||
\subsection ui_tree_ds Data Sources
|
\subsection ui_tree_ds Data Sources
|
||||||
|
|
||||||
|
32
docs/doxygen-user/volatility_dsp.dox
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*! \page volatility_dsp_page Volatility Data Source Processor
|
||||||
|
|
||||||
|
\section Overview
|
||||||
|
|
||||||
|
The Volatility data source processor runs Volatility on a memory image and saves the individual Volatility module results. If the disk image associated with the memory image is also available, it will create Interesting Item artifacts linking the Volatility results to files in the disk image.
|
||||||
|
|
||||||
|
\section Usage
|
||||||
|
|
||||||
|
If you have a disk image associated with your memory image, ingest the disk image into the case first. Then go to "Add Data Source" and select "Memory Image File".
|
||||||
|
|
||||||
|
\image html volatility_dsp_select.png
|
||||||
|
|
||||||
|
On the next screen, you can select your memory image and then adjust the settings to choose a profile and which Volatility plugins to run.
|
||||||
|
|
||||||
|
\image html volatility_dsp_config.png
|
||||||
|
|
||||||
|
Next you'll see the ingest module configuration panel. No ingest modules will be run when using the Volatility data source processor, so simply hit the "Next" button. When it finishes, you may have some non-critical errors. These frequently come from the data source processor being unable to find files in the original disk image. If you did not add the associated disk image before running the Volatility data source processor on the memory image, there will be a large number of these errors but the Volatility module output will still be available.
|
||||||
|
|
||||||
|
\section Results
|
||||||
|
|
||||||
|
There are two types of results that come from running the Volatility data source processor: Module Output and Interesting Items (if the disk image was added). The Module Output section is found under the memory image in the tree.
|
||||||
|
|
||||||
|
\image html volatility_dsp_module_output.PNG
|
||||||
|
|
||||||
|
You can also view the Volatility output under "ModuleOutput/Volatility" in the Autopsy case folder. The Interesting Items link file paths found by Volatility with files in the disk image. If a disk image was not added, there will not be any Interesting Items.
|
||||||
|
|
||||||
|
\image html volatility_dsp_interesting_items.PNG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
@ -1,5 +1,5 @@
|
|||||||
<hr/>
|
<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
|
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>.
|
<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>
|
</i></p>
|
||||||
|