mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 00:16:16 +00:00
Merge branch 'release-4.12.0' of github.com:sleuthkit/autopsy into diagnostics_tool_5119
This commit is contained in:
commit
d726b44f48
@ -75,7 +75,7 @@ file.reference.javax.ws.rs-api-2.0.1.jar=release/modules/ext/javax.ws.rs-api-2.0
|
|||||||
file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar
|
file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar
|
||||||
file.reference.cxf-rt-frontend-jaxrs-3.0.16.jar=release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar
|
file.reference.cxf-rt-frontend-jaxrs-3.0.16.jar=release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar
|
||||||
file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-transports-http-3.0.16.jar
|
file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-transports-http-3.0.16.jar
|
||||||
file.reference.sleuthkit-postgresql-4.6.6.jar=release/modules/ext/sleuthkit-postgresql-4.6.6.jar
|
file.reference.sleuthkit-postgresql-4.6.7.jar=release/modules/ext/sleuthkit-postgresql-4.6.7.jar
|
||||||
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
|
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
|
||||||
file.reference.curator-framework-2.8.0.jar=release/modules/ext/curator-framework-2.8.0.jar
|
file.reference.curator-framework-2.8.0.jar=release/modules/ext/curator-framework-2.8.0.jar
|
||||||
file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0.jar
|
file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0.jar
|
||||||
|
@ -482,8 +482,8 @@
|
|||||||
<binary-origin>release\modules\ext\jmatio-1.5.jar</binary-origin>
|
<binary-origin>release\modules\ext\jmatio-1.5.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.6.jar</runtime-relative-path>
|
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.7.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.6.jar</binary-origin>
|
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.7.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/tika-parsers-1.20.jar</runtime-relative-path>
|
<runtime-relative-path>ext/tika-parsers-1.20.jar</runtime-relative-path>
|
||||||
|
@ -175,7 +175,7 @@ final class OccurrencePanel extends javax.swing.JPanel {
|
|||||||
org.openide.awt.Mnemonics.setLocalizedText(knownStatusLabel, Bundle.OccurrencePanel_commonPropertyKnownStatusLabel_text());
|
org.openide.awt.Mnemonics.setLocalizedText(knownStatusLabel, Bundle.OccurrencePanel_commonPropertyKnownStatusLabel_text());
|
||||||
addItemToBag(gridY, 0, 0, 0, knownStatusLabel);
|
addItemToBag(gridY, 0, 0, 0, knownStatusLabel);
|
||||||
javax.swing.JLabel knownStatusValue = new javax.swing.JLabel();
|
javax.swing.JLabel knownStatusValue = new javax.swing.JLabel();
|
||||||
knownStatusValue.setText(knownStatus.toString());
|
knownStatusValue.setText(knownStatus.getName());
|
||||||
if (knownStatus == TskData.FileKnown.BAD) {
|
if (knownStatus == TskData.FileKnown.BAD) {
|
||||||
knownStatusValue.setForeground(Color.RED);
|
knownStatusValue.setForeground(Color.RED);
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="12" weightX="0.0" weightY="0.0"/>
|
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="5" anchor="12" weightX="0.0" weightY="0.0"/>
|
||||||
</Constraint>
|
</Constraint>
|
||||||
</Constraints>
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
@ -95,7 +95,7 @@
|
|||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
|
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
</Constraint>
|
</Constraint>
|
||||||
</Constraints>
|
</Constraints>
|
||||||
|
|
||||||
@ -464,7 +464,7 @@
|
|||||||
<Container class="javax.swing.JPanel" name="accountTypeListPane">
|
<Container class="javax.swing.JPanel" name="accountTypeListPane">
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
||||||
<Property name="axis" type="int" value="1"/>
|
<Property name="axis" type="int" value="3"/>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Container>
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
|
@ -53,6 +53,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
|
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent.COMPLETED;
|
||||||
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED;
|
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED;
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
@ -63,6 +64,7 @@ import org.sleuthkit.datamodel.CommunicationsFilter.AccountTypeFilter;
|
|||||||
import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter;
|
import org.sleuthkit.datamodel.CommunicationsFilter.DateRangeFilter;
|
||||||
import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
|
import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
|
||||||
import org.sleuthkit.datamodel.CommunicationsFilter.MostRecentFilter;
|
import org.sleuthkit.datamodel.CommunicationsFilter.MostRecentFilter;
|
||||||
|
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
|
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
|
||||||
import static org.sleuthkit.datamodel.Relationship.Type.CONTACT;
|
import static org.sleuthkit.datamodel.Relationship.Type.CONTACT;
|
||||||
@ -96,9 +98,10 @@ final public class FiltersPanel extends JPanel {
|
|||||||
* Listens to ingest events to enable refresh button
|
* Listens to ingest events to enable refresh button
|
||||||
*/
|
*/
|
||||||
private final PropertyChangeListener ingestListener;
|
private final PropertyChangeListener ingestListener;
|
||||||
|
private final PropertyChangeListener ingestJobListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag that indicates the UI is not up-sto-date with respect to the case DB
|
* Flag that indicates the UI is not up-to-date with respect to the case DB
|
||||||
* and it should be refreshed (by reapplying the filters).
|
* and it should be refreshed (by reapplying the filters).
|
||||||
*/
|
*/
|
||||||
private boolean needsRefresh;
|
private boolean needsRefresh;
|
||||||
@ -123,6 +126,11 @@ final public class FiltersPanel extends JPanel {
|
|||||||
@NbBundle.Messages({"refreshText=Refresh Results", "applyText=Apply"})
|
@NbBundle.Messages({"refreshText=Refresh Results", "applyText=Apply"})
|
||||||
public FiltersPanel() {
|
public FiltersPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
|
CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(Account.Type.DEVICE, true);
|
||||||
|
accountTypeMap.put(Account.Type.DEVICE, panel.getCheckBox());
|
||||||
|
accountTypeListPane.add(panel);
|
||||||
|
|
||||||
deviceRequiredLabel.setVisible(false);
|
deviceRequiredLabel.setVisible(false);
|
||||||
accountTypeRequiredLabel.setVisible(false);
|
accountTypeRequiredLabel.setVisible(false);
|
||||||
startDatePicker.setDate(LocalDate.now().minusWeeks(3));
|
startDatePicker.setDate(LocalDate.now().minusWeeks(3));
|
||||||
@ -155,18 +163,30 @@ final public class FiltersPanel extends JPanel {
|
|||||||
// Indicate that a refresh may be needed, unless the data added is Keyword or Hashset hits
|
// Indicate that a refresh may be needed, unless the data added is Keyword or Hashset hits
|
||||||
ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue();
|
ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue();
|
||||||
if (null != eventData
|
if (null != eventData
|
||||||
&& eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
|
&& (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|
||||||
&& eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
|
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|
||||||
updateFilters(false);
|
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
||||||
|
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()))
|
||||||
|
{
|
||||||
|
updateFilters(true);
|
||||||
needsRefresh = true;
|
needsRefresh = true;
|
||||||
validateFilters();
|
validateFilters();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.ingestJobListener = pce -> {
|
||||||
|
String eventType = pce.getPropertyName();
|
||||||
|
if (eventType.equals(COMPLETED.toString()) &&
|
||||||
|
updateFilters(true)) {
|
||||||
|
|
||||||
|
needsRefresh = true;
|
||||||
|
validateFilters();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
applyFiltersButton.addActionListener(e -> applyFilters());
|
applyFiltersButton.addActionListener(e -> applyFilters());
|
||||||
refreshButton.addActionListener(e -> applyFilters());
|
refreshButton.addActionListener(e -> applyFilters());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,19 +239,26 @@ final public class FiltersPanel extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Updates the filter widgets to reflect he data sources/types in the case.
|
* Updates the filter widgets to reflect he data sources/types in the case.
|
||||||
*/
|
*/
|
||||||
private void updateFilters(boolean initialState) {
|
private boolean updateFilters(boolean initialState) {
|
||||||
updateAccountTypeFilter();
|
boolean newAccountType = updateAccountTypeFilter(initialState);
|
||||||
updateDeviceFilter(initialState);
|
boolean newDeviceFilter = updateDeviceFilter(initialState);
|
||||||
|
|
||||||
|
// both or either are true, return true;
|
||||||
|
return newAccountType || newDeviceFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addNotify() {
|
public void addNotify() {
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(ingestListener);
|
IngestManager.getInstance().addIngestModuleEventListener(ingestListener);
|
||||||
|
IngestManager.getInstance().addIngestJobEventListener(ingestJobListener);
|
||||||
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
|
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
|
||||||
//clear the device filter widget when the case changes.
|
//clear the device filter widget when the case changes.
|
||||||
devicesMap.clear();
|
devicesMap.clear();
|
||||||
devicesListPane.removeAll();
|
devicesListPane.removeAll();
|
||||||
|
|
||||||
|
accountTypeMap.clear();
|
||||||
|
accountTypeListPane.removeAll();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,64 +266,107 @@ final public class FiltersPanel extends JPanel {
|
|||||||
public void removeNotify() {
|
public void removeNotify() {
|
||||||
super.removeNotify();
|
super.removeNotify();
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(ingestListener);
|
IngestManager.getInstance().removeIngestModuleEventListener(ingestListener);
|
||||||
|
IngestManager.getInstance().removeIngestJobEventListener(ingestJobListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate the Account Types filter widgets
|
* Populate the Account Types filter widgets
|
||||||
|
*
|
||||||
|
* @param selected the initial value for the account type checkbox
|
||||||
|
*
|
||||||
|
* @return True, if a new accountType was found
|
||||||
*/
|
*/
|
||||||
private void updateAccountTypeFilter() {
|
private boolean updateAccountTypeFilter(boolean selected) {
|
||||||
|
boolean newOneFound = false;
|
||||||
|
try {
|
||||||
|
final CommunicationsManager communicationsManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
|
||||||
|
List<Account.Type> accountTypesInUse = communicationsManager.getAccountTypesInUse();
|
||||||
|
|
||||||
//TODO: something like this commented code could be used to show only
|
for (Account.Type type : accountTypesInUse) {
|
||||||
//the account types that are found:
|
|
||||||
//final CommunicationsManager communicationsManager = Case.getCurrentOpenCase().getSleuthkitCase().getCommunicationsManager();
|
|
||||||
//List<Account.Type> accountTypesInUse = communicationsManager.getAccountTypesInUse();
|
|
||||||
//accountTypesInUSe.forEach(...)
|
|
||||||
Account.Type.PREDEFINED_ACCOUNT_TYPES.forEach(type -> {
|
|
||||||
if (type.equals(Account.Type.CREDIT_CARD)) {
|
|
||||||
//don't show a check box for credit cards
|
|
||||||
} else {
|
|
||||||
accountTypeMap.computeIfAbsent(type, t -> {
|
|
||||||
|
|
||||||
|
if (!accountTypeMap.containsKey(type) && !type.equals(Account.Type.CREDIT_CARD)) {
|
||||||
|
CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(type, selected);
|
||||||
|
accountTypeMap.put(type, panel.getCheckBox());
|
||||||
|
accountTypeListPane.add(panel);
|
||||||
|
|
||||||
|
newOneFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Unable to update to update Account Types Filter", ex);
|
||||||
|
} catch (NoCurrentCaseException ex) {
|
||||||
|
logger.log(Level.WARNING, "A case is required to update the account types filter.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newOneFound) {
|
||||||
|
accountTypeListPane.revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newOneFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to create a new instance of the CheckBoxIconPanel base on
|
||||||
|
* the Account.Type and initalState (check box state).
|
||||||
|
*
|
||||||
|
* @param type Account.Type to display on the panel
|
||||||
|
* @param initalState initial check box state
|
||||||
|
*
|
||||||
|
* @return instance of the CheckBoxIconPanel
|
||||||
|
*/
|
||||||
|
private CheckBoxIconPanel createAccoutTypeCheckBoxPanel(Account.Type type, boolean initalState) {
|
||||||
CheckBoxIconPanel panel = new CheckBoxIconPanel(
|
CheckBoxIconPanel panel = new CheckBoxIconPanel(
|
||||||
type.getDisplayName(),
|
type.getDisplayName(),
|
||||||
new ImageIcon(FiltersPanel.class.getResource(Utils.getIconFilePath(type))));
|
new ImageIcon(FiltersPanel.class.getResource(Utils.getIconFilePath(type))));
|
||||||
panel.setSelected(true);
|
|
||||||
|
panel.setSelected(initalState);
|
||||||
panel.addItemListener(validationListener);
|
panel.addItemListener(validationListener);
|
||||||
accountTypeListPane.add(panel);
|
if (type.equals(Account.Type.DEVICE)) {
|
||||||
if (t.equals(Account.Type.DEVICE)) {
|
|
||||||
//Deveice type filter is enabled based on whether we are in table or graph view.
|
//Deveice type filter is enabled based on whether we are in table or graph view.
|
||||||
panel.setEnabled(deviceAccountTypeEnabled);
|
panel.setEnabled(deviceAccountTypeEnabled);
|
||||||
}
|
}
|
||||||
return panel.getCheckBox();
|
|
||||||
});
|
return panel;
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate the devices filter widgets
|
* Populate the devices filter widgets
|
||||||
*
|
*
|
||||||
* @param initialState
|
* @param selected Sets the initial state of device check box
|
||||||
|
*
|
||||||
|
* @return true if a new device was found
|
||||||
*/
|
*/
|
||||||
private void updateDeviceFilter(boolean initialState) {
|
private boolean updateDeviceFilter(boolean selected) {
|
||||||
|
boolean newOneFound = false;
|
||||||
try {
|
try {
|
||||||
final SleuthkitCase sleuthkitCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
final SleuthkitCase sleuthkitCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
||||||
|
|
||||||
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
|
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
|
||||||
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
|
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
|
||||||
//store the device id in the map, but display a datasource name in the UI.
|
if(devicesMap.containsKey(dataSource.getDeviceId())) {
|
||||||
devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> {
|
continue;
|
||||||
final JCheckBox jCheckBox = new JCheckBox(dsName, initialState);
|
}
|
||||||
|
|
||||||
|
final JCheckBox jCheckBox = new JCheckBox(dsName, selected);
|
||||||
jCheckBox.addItemListener(validationListener);
|
jCheckBox.addItemListener(validationListener);
|
||||||
devicesListPane.add(jCheckBox);
|
devicesListPane.add(jCheckBox);
|
||||||
return jCheckBox;
|
devicesMap.put(dataSource.getDeviceId(), jCheckBox);
|
||||||
});
|
|
||||||
|
newOneFound = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException ex) {
|
} catch (NoCurrentCaseException ex) {
|
||||||
logger.log(Level.INFO, "Filter update cancelled. Case is closed.");
|
logger.log(Level.INFO, "Filter update cancelled. Case is closed.");
|
||||||
} catch (TskCoreException tskCoreException) {
|
} catch (TskCoreException tskCoreException) {
|
||||||
logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", tskCoreException);
|
logger.log(Level.SEVERE, "There was a error loading the datasources for the case.", tskCoreException);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(newOneFound) {
|
||||||
|
devicesListPane.revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return newOneFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -319,7 +389,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the state of the device filter checkboxes
|
* Sets the state of the device filter check boxes
|
||||||
*
|
*
|
||||||
* @param deviceFilter Selected devices
|
* @param deviceFilter Selected devices
|
||||||
*/
|
*/
|
||||||
@ -366,6 +436,12 @@ final public class FiltersPanel extends JPanel {
|
|||||||
endDatePicker.setEnabled(state.isEnabled());
|
endDatePicker.setEnabled(state.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the state of the most recent UI controls based on the current values
|
||||||
|
* in MostRecentFilter.
|
||||||
|
*
|
||||||
|
* @param filter The MostRecentFilter state to be set
|
||||||
|
*/
|
||||||
private void setMostRecentFilter(MostRecentFilter filter) {
|
private void setMostRecentFilter(MostRecentFilter filter) {
|
||||||
int limit = filter.getLimit();
|
int limit = filter.getLimit();
|
||||||
if(limit > 0) {
|
if(limit > 0) {
|
||||||
@ -424,6 +500,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
gridBagConstraints.gridx = 1;
|
gridBagConstraints.gridx = 1;
|
||||||
gridBagConstraints.gridy = 0;
|
gridBagConstraints.gridy = 0;
|
||||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
|
||||||
topPane.add(applyFiltersButton, gridBagConstraints);
|
topPane.add(applyFiltersButton, gridBagConstraints);
|
||||||
|
|
||||||
needsRefreshLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.needsRefreshLabel.text")); // NOI18N
|
needsRefreshLabel.setText(org.openide.util.NbBundle.getMessage(FiltersPanel.class, "FiltersPanel.needsRefreshLabel.text")); // NOI18N
|
||||||
@ -697,7 +774,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
|
|
||||||
accountTypesScrollPane.setPreferredSize(new java.awt.Dimension(2, 200));
|
accountTypesScrollPane.setPreferredSize(new java.awt.Dimension(2, 200));
|
||||||
|
|
||||||
accountTypeListPane.setLayout(new javax.swing.BoxLayout(accountTypeListPane, javax.swing.BoxLayout.Y_AXIS));
|
accountTypeListPane.setLayout(new javax.swing.BoxLayout(accountTypeListPane, javax.swing.BoxLayout.PAGE_AXIS));
|
||||||
accountTypesScrollPane.setViewportView(accountTypeListPane);
|
accountTypesScrollPane.setViewportView(accountTypeListPane);
|
||||||
|
|
||||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
@ -740,6 +817,7 @@ final public class FiltersPanel extends JPanel {
|
|||||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
gridBagConstraints.weightx = 1.0;
|
gridBagConstraints.weightx = 1.0;
|
||||||
gridBagConstraints.weighty = 1.0;
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0);
|
||||||
add(scrollPane, gridBagConstraints);
|
add(scrollPane, gridBagConstraints);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
@ -808,6 +886,11 @@ final public class FiltersPanel extends JPanel {
|
|||||||
endCheckBox.isSelected() ? endDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0);
|
endCheckBox.isSelected() ? endDatePicker.getDate().atStartOfDay(zone).toEpochSecond() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a MostRecentFilter that based on the current state of the ui controls.
|
||||||
|
*
|
||||||
|
* @return A new instance of MostRecentFilter
|
||||||
|
*/
|
||||||
private MostRecentFilter getMostRecentFilter() {
|
private MostRecentFilter getMostRecentFilter() {
|
||||||
String value = (String)limitComboBox.getSelectedItem();
|
String value = (String)limitComboBox.getSelectedItem();
|
||||||
if(value.trim().equalsIgnoreCase("all")){
|
if(value.trim().equalsIgnoreCase("all")){
|
||||||
|
BIN
Core/src/org/sleuthkit/autopsy/communications/images/nail.png
Executable file
BIN
Core/src/org/sleuthkit/autopsy/communications/images/nail.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 202 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/screw.png
Executable file
BIN
Core/src/org/sleuthkit/autopsy/communications/images/screw.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 217 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/threaded.png
Executable file
BIN
Core/src/org/sleuthkit/autopsy/communications/images/threaded.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 263 B |
BIN
Core/src/org/sleuthkit/autopsy/communications/images/unthreaded.png
Executable file
BIN
Core/src/org/sleuthkit/autopsy/communications/images/unthreaded.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 199 B |
@ -11,5 +11,13 @@ SummaryViewer.emailDataLabel.text=emails
|
|||||||
SummaryViewer.attachmentsDataLabel.text=attachments
|
SummaryViewer.attachmentsDataLabel.text=attachments
|
||||||
SummaryViewer.messagesLabel.text=Messages:
|
SummaryViewer.messagesLabel.text=Messages:
|
||||||
SummaryViewer.callLogsLabel.text=Call Logs:
|
SummaryViewer.callLogsLabel.text=Call Logs:
|
||||||
|
ThreadRootMessagePanel.showAllCheckBox.text=Show All Messages
|
||||||
|
ThreadPane.backButton.text=<---
|
||||||
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
|
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
|
||||||
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
|
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
|
||||||
|
MessageViewer.threadsLabel.text=Select a Thread to View
|
||||||
|
MessageViewer.threadNameLabel.text=<threadName>
|
||||||
|
MessageViewer.showingMessagesLabel.text=Showing Messages for Thread:
|
||||||
|
MessageViewer.backButton.AccessibleContext.accessibleDescription=
|
||||||
|
MessageViewer.backButton.text=Threads
|
||||||
|
MessageViewer.showAllButton.text=All Messages
|
||||||
|
@ -19,12 +19,16 @@ MessageNode_Node_Property_Subject=Subject
|
|||||||
MessageNode_Node_Property_To=To
|
MessageNode_Node_Property_To=To
|
||||||
MessageNode_Node_Property_Type=Type
|
MessageNode_Node_Property_Type=Type
|
||||||
MessageViewer_columnHeader_Attms=Attachments
|
MessageViewer_columnHeader_Attms=Attachments
|
||||||
MessageViewer_columnHeader_Date=Date
|
MessageViewer_columnHeader_Date=Data
|
||||||
|
MessageViewer_columnHeader_EarlyDate=Earliest Message
|
||||||
MessageViewer_columnHeader_From=From
|
MessageViewer_columnHeader_From=From
|
||||||
MessageViewer_columnHeader_Subject=Subject
|
MessageViewer_columnHeader_Subject=Subject
|
||||||
MessageViewer_columnHeader_To=To
|
MessageViewer_columnHeader_To=To
|
||||||
MessageViewer_no_messages=<No messages found for selected account>
|
MessageViewer_no_messages=<No messages found for selected account>
|
||||||
MessageViewer_tabTitle=Messages
|
MessageViewer_tabTitle=Messages
|
||||||
|
MessageViewer_viewMessage_all=All
|
||||||
|
MessageViewer_viewMessage_selected=Selected
|
||||||
|
MessageViewer_viewMessage_unthreaded=Unthreaded
|
||||||
SummaryViewer.countsPanel.border.title=Counts
|
SummaryViewer.countsPanel.border.title=Counts
|
||||||
SummaryViewer.emailLabel.text=Emails:
|
SummaryViewer.emailLabel.text=Emails:
|
||||||
SummaryViewer.contactsLabel.text=Contacts:
|
SummaryViewer.contactsLabel.text=Contacts:
|
||||||
@ -37,11 +41,19 @@ SummaryViewer.emailDataLabel.text=emails
|
|||||||
SummaryViewer.attachmentsDataLabel.text=attachments
|
SummaryViewer.attachmentsDataLabel.text=attachments
|
||||||
SummaryViewer.messagesLabel.text=Messages:
|
SummaryViewer.messagesLabel.text=Messages:
|
||||||
SummaryViewer.callLogsLabel.text=Call Logs:
|
SummaryViewer.callLogsLabel.text=Call Logs:
|
||||||
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
|
|
||||||
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
|
|
||||||
SummaryViewer_CaseRefNameColumn_Title=Case Name
|
SummaryViewer_CaseRefNameColumn_Title=Case Name
|
||||||
SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Other Occurrences>
|
SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Other Occurrences>
|
||||||
SummaryViewer_Creation_Date_Title=Creation Date
|
SummaryViewer_Creation_Date_Title=Creation Date
|
||||||
SummaryViewer_FileRefNameColumn_Title=Path
|
SummaryViewer_FileRefNameColumn_Title=Path
|
||||||
SummaryViewer_TabTitle=Summary
|
SummaryViewer_TabTitle=Summary
|
||||||
SummeryViewer_FileRef_Message=<Select one Accout to see File References>
|
SummeryViewer_FileRef_Message=<Select one Accout to see File References>
|
||||||
|
ThreadRootMessagePanel.showAllCheckBox.text=Show All Messages
|
||||||
|
ThreadPane.backButton.text=<---
|
||||||
|
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
|
||||||
|
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
|
||||||
|
MessageViewer.threadsLabel.text=Select a Thread to View
|
||||||
|
MessageViewer.threadNameLabel.text=<threadName>
|
||||||
|
MessageViewer.showingMessagesLabel.text=Showing Messages for Thread:
|
||||||
|
MessageViewer.backButton.AccessibleContext.accessibleDescription=
|
||||||
|
MessageViewer.backButton.text=Threads
|
||||||
|
MessageViewer.showAllButton.text=All Messages
|
||||||
|
@ -17,34 +17,7 @@
|
|||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="propertySheet" max="32767" attributes="0"/>
|
|
||||||
<Group type="102" attributes="0">
|
|
||||||
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="propertySheet" pref="283" max="32767" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JLabel" name="nameLabel">
|
<Component class="javax.swing.JLabel" name="nameLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -55,11 +28,21 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="ContactDetailsPane.nameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="ContactDetailsPane.nameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="16" insetsLeft="15" insetsBottom="15" insetsRight="15" anchor="23" weightX="1.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="org.openide.explorer.propertysheet.PropertySheet" name="propertySheet">
|
<Component class="org.openide.explorer.propertysheet.PropertySheet" name="propertySheet">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="descriptionAreaVisible" type="boolean" value="false"/>
|
<Property name="descriptionAreaVisible" type="boolean" value="false"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="1" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="15" insetsBottom="16" insetsRight="15" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -73,38 +73,36 @@ public final class ContactDetailsPane extends javax.swing.JPanel implements Expl
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
messageContentViewer1 = new org.sleuthkit.autopsy.contentviewers.MessageContentViewer();
|
messageContentViewer1 = new org.sleuthkit.autopsy.contentviewers.MessageContentViewer();
|
||||||
nameLabel = new javax.swing.JLabel();
|
nameLabel = new javax.swing.JLabel();
|
||||||
propertySheet = new org.openide.explorer.propertysheet.PropertySheet();
|
propertySheet = new org.openide.explorer.propertysheet.PropertySheet();
|
||||||
|
|
||||||
|
setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
nameLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
|
nameLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ContactDetailsPane.class, "ContactDetailsPane.nameLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ContactDetailsPane.class, "ContactDetailsPane.nameLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(16, 15, 15, 15);
|
||||||
|
add(nameLabel, gridBagConstraints);
|
||||||
|
|
||||||
propertySheet.setDescriptionAreaVisible(false);
|
propertySheet.setDescriptionAreaVisible(false);
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
gridBagConstraints.gridx = 0;
|
||||||
this.setLayout(layout);
|
gridBagConstraints.gridy = 1;
|
||||||
layout.setHorizontalGroup(
|
gridBagConstraints.gridwidth = 2;
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
.addGroup(layout.createSequentialGroup()
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
.addContainerGap()
|
gridBagConstraints.weightx = 1.0;
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
gridBagConstraints.weighty = 1.0;
|
||||||
.addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
gridBagConstraints.insets = new java.awt.Insets(9, 15, 16, 15);
|
||||||
.addGroup(layout.createSequentialGroup()
|
add(propertySheet, gridBagConstraints);
|
||||||
.addComponent(nameLabel)
|
|
||||||
.addGap(0, 0, Short.MAX_VALUE)))
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
layout.setVerticalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addContainerGap()
|
|
||||||
.addComponent(nameLabel)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE)
|
|
||||||
.addContainerGap())
|
|
||||||
);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
* ChildFactory for ContactNodes.
|
* ChildFactory for ContactNodes.
|
||||||
*/
|
*/
|
||||||
final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
|
final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
|
||||||
private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName());
|
private static final Logger logger = Logger.getLogger(ContactsChildNodeFactory.class.getName());
|
||||||
|
|
||||||
private SelectionInfo selectionInfo;
|
private SelectionInfo selectionInfo;
|
||||||
|
|
||||||
|
@ -130,9 +130,7 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
|
|||||||
logger.log(Level.WARNING, "Unable to update selection." , ex);
|
logger.log(Level.WARNING, "Unable to update selection." , ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(artifactList.size() == 0) {
|
|
||||||
thumbnailViewer.resetComponent();
|
thumbnailViewer.resetComponent();
|
||||||
}
|
|
||||||
|
|
||||||
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new AttachmentsChildren(artifactList)), tableEM), true, this.getClass().getName()));
|
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new AttachmentsChildren(artifactList)), tableEM), true, this.getClass().getName()));
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,11 @@ package org.sleuthkit.autopsy.communications.relationships;
|
|||||||
|
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.Action;
|
||||||
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.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -40,20 +40,31 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBU
|
|||||||
import org.sleuthkit.datamodel.TimeUtilities;
|
import org.sleuthkit.datamodel.TimeUtilities;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.autopsy.communications.Utils;
|
import org.sleuthkit.autopsy.communications.Utils;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView
|
* Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView
|
||||||
*/
|
*/
|
||||||
final class MessageNode extends BlackboardArtifactNode {
|
class MessageNode extends BlackboardArtifactNode {
|
||||||
|
|
||||||
|
public static final String UNTHREADED_ID = "<UNTHREADED>";
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(MessageNode.class.getName());
|
private static final Logger logger = Logger.getLogger(MessageNode.class.getName());
|
||||||
|
|
||||||
MessageNode(BlackboardArtifact artifact) {
|
private final String threadID;
|
||||||
|
|
||||||
|
private final Action preferredAction;
|
||||||
|
|
||||||
|
MessageNode(BlackboardArtifact artifact, String threadID, Action preferredAction) {
|
||||||
super(artifact);
|
super(artifact);
|
||||||
|
|
||||||
|
this.preferredAction = preferredAction;
|
||||||
|
|
||||||
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS
|
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS
|
||||||
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS
|
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS
|
||||||
setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase);
|
setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase);
|
||||||
|
|
||||||
|
this.threadID = threadID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Messages({
|
@Messages({
|
||||||
@ -76,6 +87,8 @@ final class MessageNode extends BlackboardArtifactNode {
|
|||||||
|
|
||||||
sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS
|
sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS
|
||||||
|
|
||||||
|
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",threadID == null ? UNTHREADED_ID : threadID)); //NON-NLS
|
||||||
|
|
||||||
final BlackboardArtifact artifact = getArtifact();
|
final BlackboardArtifact artifact = getArtifact();
|
||||||
|
|
||||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
||||||
@ -167,4 +180,13 @@ final class MessageNode extends BlackboardArtifactNode {
|
|||||||
public String getSourceName() {
|
public String getSourceName() {
|
||||||
return getDisplayName();
|
return getDisplayName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getThreadID() {
|
||||||
|
return threadID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action getPreferredAction() {
|
||||||
|
return preferredAction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
140
Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form
Executable file
140
Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.form
Executable file
@ -0,0 +1,140 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,3,-126,0,0,2,-76"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignCardLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Container class="javax.swing.JPanel" name="rootMessagesPane">
|
||||||
|
<Properties>
|
||||||
|
<Property name="opaque" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
|
||||||
|
<CardConstraints cardName="threads"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JLabel" name="threadsLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.threadsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="15" insetsBottom="9" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="showAllButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.showAllButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showAllButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="15" insetsBottom="15" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="rootTablePane">
|
||||||
|
<Properties>
|
||||||
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
|
<Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
|
||||||
|
<LineBorder/>
|
||||||
|
</Border>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="1" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="15" insetsBottom="9" insetsRight="15" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
<Container class="javax.swing.JPanel" name="messagePanel">
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
|
||||||
|
<CardConstraints cardName="messages"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="org.sleuthkit.autopsy.communications.relationships.MessagesPanel" name="threadMessagesPanel">
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessagesPanel()"/>
|
||||||
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="3" gridWidth="3" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="15" insetsBottom="0" insetsRight="15" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="backButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.backButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<AccessibilityProperties>
|
||||||
|
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.backButton.AccessibleContext.accessibleDescription" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</AccessibilityProperties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="backButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="0" insetsBottom="9" insetsRight="15" anchor="13" weightX="1.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="showingMessagesLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.showingMessagesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="15" insetsBottom="5" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="threadNameLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="MessageViewer.threadNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
|
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="9" insetsLeft="5" insetsBottom="5" insetsRight="15" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
439
Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java
Executable file
439
Core/src/org/sleuthkit/autopsy/communications/relationships/MessageViewer.java
Executable file
@ -0,0 +1,439 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 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.communications.relationships;
|
||||||
|
|
||||||
|
import java.awt.CardLayout;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.KeyboardFocusManager;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.beans.PropertyVetoException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import static javax.swing.SwingUtilities.isDescendingFrom;
|
||||||
|
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||||
|
import org.netbeans.swing.outline.Outline;
|
||||||
|
import org.openide.explorer.ExplorerManager;
|
||||||
|
import static org.openide.explorer.ExplorerUtils.createLookup;
|
||||||
|
import org.openide.nodes.AbstractNode;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
|
import org.openide.nodes.Node.Property;
|
||||||
|
import org.openide.nodes.Node.PropertySet;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
|
import org.openide.util.Lookup;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main panel for the messages tab of the RelationshipViewer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
|
public class MessageViewer extends JPanel implements RelationshipsViewer {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(MessageViewer.class.getName());
|
||||||
|
|
||||||
|
private final ModifiableProxyLookup proxyLookup;
|
||||||
|
private final PropertyChangeListener focusPropertyListener;
|
||||||
|
private final ThreadChildNodeFactory rootMessageFactory;
|
||||||
|
private final MessagesChildNodeFactory threadMessageNodeFactory;
|
||||||
|
|
||||||
|
private SelectionInfo currentSelectionInfo = null;
|
||||||
|
|
||||||
|
OutlineViewPanel currentPanel;
|
||||||
|
|
||||||
|
@Messages({
|
||||||
|
"MessageViewer_tabTitle=Messages",
|
||||||
|
"MessageViewer_columnHeader_From=From",
|
||||||
|
"MessageViewer_columnHeader_Date=Data",
|
||||||
|
"MessageViewer_columnHeader_To=To",
|
||||||
|
"MessageViewer_columnHeader_EarlyDate=Earliest Message",
|
||||||
|
"MessageViewer_columnHeader_Subject=Subject",
|
||||||
|
"MessageViewer_columnHeader_Attms=Attachments",
|
||||||
|
"MessageViewer_no_messages=<No messages found for selected account>",
|
||||||
|
"MessageViewer_viewMessage_all=All",
|
||||||
|
"MessageViewer_viewMessage_selected=Selected",
|
||||||
|
"MessageViewer_viewMessage_unthreaded=Unthreaded",})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new form MessageViewer
|
||||||
|
*/
|
||||||
|
public MessageViewer() {
|
||||||
|
|
||||||
|
initComponents();
|
||||||
|
currentPanel = rootTablePane;
|
||||||
|
proxyLookup = new ModifiableProxyLookup(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
|
||||||
|
rootMessageFactory = new ThreadChildNodeFactory(new ShowThreadMessagesAction());
|
||||||
|
threadMessageNodeFactory = new MessagesChildNodeFactory();
|
||||||
|
|
||||||
|
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
|
||||||
|
// explaination of focusPropertyListener
|
||||||
|
focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
|
||||||
|
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
|
||||||
|
final Component newFocusOwner = (Component) focusEvent.getNewValue();
|
||||||
|
|
||||||
|
if (newFocusOwner == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isDescendingFrom(newFocusOwner, rootTablePane)) {
|
||||||
|
proxyLookup.setNewLookups(createLookup(rootTablePane.getExplorerManager(), getActionMap()));
|
||||||
|
} else if (isDescendingFrom(newFocusOwner, MessageViewer.this)) {
|
||||||
|
proxyLookup.setNewLookups(createLookup(currentPanel.getExplorerManager(), getActionMap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rootTablePane.getExplorerManager().setRootContext(
|
||||||
|
new AbstractNode(Children.create(rootMessageFactory, true)));
|
||||||
|
|
||||||
|
rootTablePane.getOutlineView().setPopupAllowed(false);
|
||||||
|
|
||||||
|
Outline outline = rootTablePane.getOutlineView().getOutline();
|
||||||
|
rootTablePane.getOutlineView().setPropertyColumns(
|
||||||
|
"Date", Bundle.MessageViewer_columnHeader_EarlyDate(),
|
||||||
|
"Subject", Bundle.MessageViewer_columnHeader_Subject()
|
||||||
|
);
|
||||||
|
outline.setRootVisible(false);
|
||||||
|
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Type");
|
||||||
|
outline.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
|
||||||
|
|
||||||
|
rootTablePane.getExplorerManager().addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
||||||
|
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||||
|
showSelectedThread();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
threadMessagesPanel.setChildFactory(threadMessageNodeFactory);
|
||||||
|
|
||||||
|
rootTablePane.setTableColumnsWidth(10, 20, 70);
|
||||||
|
|
||||||
|
Image image = getScaledImage((new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/timeline/images/arrow-180.png"))).getImage(), 16, 16);
|
||||||
|
backButton.setIcon(new ImageIcon(image) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return Bundle.MessageViewer_tabTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JPanel getPanel() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSelectionInfo(SelectionInfo info) {
|
||||||
|
currentSelectionInfo = info;
|
||||||
|
|
||||||
|
currentPanel = rootTablePane;
|
||||||
|
|
||||||
|
CardLayout layout = (CardLayout) this.getLayout();
|
||||||
|
layout.show(this, "threads");
|
||||||
|
|
||||||
|
rootMessageFactory.refresh(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lookup getLookup() {
|
||||||
|
return proxyLookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addNotify() {
|
||||||
|
super.addNotify();
|
||||||
|
//add listener that maintains correct selection in the Global Actions Context
|
||||||
|
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||||
|
.addPropertyChangeListener("focusOwner", focusPropertyListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeNotify() {
|
||||||
|
super.removeNotify();
|
||||||
|
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||||
|
.removePropertyChangeListener("focusOwner", focusPropertyListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private void showSelectedThread() {
|
||||||
|
final Node[] nodes = rootTablePane.getExplorerManager().getSelectedNodes();
|
||||||
|
|
||||||
|
if (nodes == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodes.length == 0 || nodes.length > 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<String> threadIDList = new ArrayList<>();
|
||||||
|
String subject = "";
|
||||||
|
|
||||||
|
PropertySet[] propertySets = nodes[0].getPropertySets();
|
||||||
|
for (PropertySet pset : propertySets) {
|
||||||
|
Property[] properties = pset.getProperties();
|
||||||
|
for (Property prop : properties) {
|
||||||
|
if (prop.getName().equalsIgnoreCase("threadid")) {
|
||||||
|
try {
|
||||||
|
String threadID = prop.getValue().toString();
|
||||||
|
if (!threadIDList.contains(threadID)) {
|
||||||
|
threadIDList.add(threadID);
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException ex) {
|
||||||
|
logger.log(Level.WARNING, String.format("Unable to get threadid for node: %s", nodes[0].getDisplayName()), ex);
|
||||||
|
}
|
||||||
|
} else if (prop.getName().equalsIgnoreCase("subject")) {
|
||||||
|
try {
|
||||||
|
subject = prop.getValue().toString();
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException ex) {
|
||||||
|
logger.log(Level.WARNING, String.format("Unable to get subject for node: %s", nodes[0].getDisplayName()), ex);
|
||||||
|
subject = "<unavailable>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!threadIDList.isEmpty()) {
|
||||||
|
threadMessageNodeFactory.refresh(currentSelectionInfo, threadIDList);
|
||||||
|
|
||||||
|
if (!subject.isEmpty()) {
|
||||||
|
threadNameLabel.setText(subject);
|
||||||
|
} else {
|
||||||
|
threadNameLabel.setText(Bundle.MessageViewer_viewMessage_unthreaded());
|
||||||
|
}
|
||||||
|
|
||||||
|
showMessagesPane();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the threads pane visible.
|
||||||
|
*/
|
||||||
|
private void showThreadsPane() {
|
||||||
|
switchCard("threads");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the message pane visible.
|
||||||
|
*/
|
||||||
|
private void showMessagesPane() {
|
||||||
|
switchCard("messages");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the visible panel (card).
|
||||||
|
*
|
||||||
|
* @param cardName Name of card to show
|
||||||
|
*/
|
||||||
|
private void switchCard(String cardName) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
CardLayout layout = (CardLayout)getLayout();
|
||||||
|
layout.show(MessageViewer.this, cardName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales the given image to the given width and height.
|
||||||
|
*
|
||||||
|
* @param srcImg Image to scale
|
||||||
|
* @param w Image width
|
||||||
|
* @param h Image height
|
||||||
|
*
|
||||||
|
* @return Scaled version of srcImg
|
||||||
|
*/
|
||||||
|
private Image getScaledImage(Image srcImg, int w, int h){
|
||||||
|
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g2 = resizedImg.createGraphics();
|
||||||
|
|
||||||
|
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||||
|
g2.drawImage(srcImg, 0, 0, w, h, null);
|
||||||
|
g2.dispose();
|
||||||
|
|
||||||
|
return resizedImg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called from within the constructor to initialize the form.
|
||||||
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
* regenerated by the Form Editor.'
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
java.awt.GridBagConstraints gridBagConstraints;
|
||||||
|
|
||||||
|
rootMessagesPane = new javax.swing.JPanel();
|
||||||
|
threadsLabel = new javax.swing.JLabel();
|
||||||
|
showAllButton = new javax.swing.JButton();
|
||||||
|
rootTablePane = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
||||||
|
messagePanel = new javax.swing.JPanel();
|
||||||
|
threadMessagesPanel = new MessagesPanel();
|
||||||
|
backButton = new javax.swing.JButton();
|
||||||
|
showingMessagesLabel = new javax.swing.JLabel();
|
||||||
|
threadNameLabel = new javax.swing.JLabel();
|
||||||
|
|
||||||
|
setLayout(new java.awt.CardLayout());
|
||||||
|
|
||||||
|
rootMessagesPane.setOpaque(false);
|
||||||
|
rootMessagesPane.setLayout(new java.awt.GridBagLayout());
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(threadsLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadsLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(15, 15, 9, 0);
|
||||||
|
rootMessagesPane.add(threadsLabel, gridBagConstraints);
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(showAllButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showAllButton.text")); // NOI18N
|
||||||
|
showAllButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
showAllButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 2;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 15, 15, 0);
|
||||||
|
rootMessagesPane.add(showAllButton, gridBagConstraints);
|
||||||
|
|
||||||
|
rootTablePane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 1;
|
||||||
|
gridBagConstraints.gridwidth = 2;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 15, 9, 15);
|
||||||
|
rootMessagesPane.add(rootTablePane, gridBagConstraints);
|
||||||
|
|
||||||
|
add(rootMessagesPane, "threads");
|
||||||
|
|
||||||
|
messagePanel.setLayout(new java.awt.GridBagLayout());
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 3;
|
||||||
|
gridBagConstraints.gridwidth = 3;
|
||||||
|
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.weighty = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(0, 15, 0, 15);
|
||||||
|
messagePanel.add(threadMessagesPanel, gridBagConstraints);
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(backButton, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.text")); // NOI18N
|
||||||
|
backButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
backButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 2;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
|
||||||
|
gridBagConstraints.weightx = 1.0;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(9, 0, 9, 15);
|
||||||
|
messagePanel.add(backButton, gridBagConstraints);
|
||||||
|
backButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.backButton.AccessibleContext.accessibleDescription")); // NOI18N
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(showingMessagesLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.showingMessagesLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(9, 15, 5, 0);
|
||||||
|
messagePanel.add(showingMessagesLabel, gridBagConstraints);
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(threadNameLabel, org.openide.util.NbBundle.getMessage(MessageViewer.class, "MessageViewer.threadNameLabel.text")); // NOI18N
|
||||||
|
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 1;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
|
||||||
|
gridBagConstraints.insets = new java.awt.Insets(9, 5, 5, 15);
|
||||||
|
messagePanel.add(threadNameLabel, gridBagConstraints);
|
||||||
|
|
||||||
|
add(messagePanel, "messages");
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
|
||||||
|
try {
|
||||||
|
rootTablePane.getExplorerManager().setSelectedNodes(new Node[0]);
|
||||||
|
} catch (PropertyVetoException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
}
|
||||||
|
showThreadsPane();
|
||||||
|
}//GEN-LAST:event_backButtonActionPerformed
|
||||||
|
|
||||||
|
private void showAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showAllButtonActionPerformed
|
||||||
|
threadMessageNodeFactory.refresh(currentSelectionInfo, null);
|
||||||
|
threadNameLabel.setText("All Messages");
|
||||||
|
|
||||||
|
showMessagesPane();
|
||||||
|
}//GEN-LAST:event_showAllButtonActionPerformed
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JButton backButton;
|
||||||
|
private javax.swing.JPanel messagePanel;
|
||||||
|
private javax.swing.JPanel rootMessagesPane;
|
||||||
|
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel rootTablePane;
|
||||||
|
private javax.swing.JButton showAllButton;
|
||||||
|
private javax.swing.JLabel showingMessagesLabel;
|
||||||
|
private org.sleuthkit.autopsy.communications.relationships.MessagesPanel threadMessagesPanel;
|
||||||
|
private javax.swing.JLabel threadNameLabel;
|
||||||
|
private javax.swing.JLabel threadsLabel;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The preferred action of the table nodes.
|
||||||
|
*/
|
||||||
|
class ShowThreadMessagesAction extends AbstractAction {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
showSelectedThread();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,52 +27,51 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
|||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ChildFactory that creates createKeys and nodes from a given selectionInfo for
|
* A ChildFactory subclass for creating MessageNodes from a set of
|
||||||
* only emails, call logs and messages.
|
* BlackboardArtifact objects.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
final class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact> {
|
public class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact>{
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName());
|
private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName());
|
||||||
|
|
||||||
private SelectionInfo selectionInfo;
|
private SelectionInfo selectionInfo;
|
||||||
|
|
||||||
/**
|
private List<String> threadIDs;
|
||||||
* Construct a new MessageChildNodeFactory from the currently selectionInfo
|
|
||||||
*
|
MessagesChildNodeFactory(SelectionInfo selectionInfo, List<String> threadIDs) {
|
||||||
* @param selectionInfo SelectionInfo object for the currently selected
|
|
||||||
* accounts
|
|
||||||
*/
|
|
||||||
MessagesChildNodeFactory(SelectionInfo selectionInfo) {
|
|
||||||
this.selectionInfo = selectionInfo;
|
this.selectionInfo = selectionInfo;
|
||||||
|
this.threadIDs = threadIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagesChildNodeFactory() {
|
||||||
|
this(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the current instance of selectionInfo and calls the refresh method.
|
* Updates the current instance of selectionInfo and calls the refresh method.
|
||||||
*
|
*
|
||||||
* @param selectionInfo New instance of the currently selected accounts
|
* @param selectionInfo New instance of the currently selected accounts
|
||||||
|
* @param threadIDs A list of threadIDs to filter the keys by, null will
|
||||||
|
* return all keys for the selected accounts.
|
||||||
*/
|
*/
|
||||||
public void refresh(SelectionInfo selectionInfo) {
|
public void refresh(SelectionInfo selectionInfo, List<String> threadIDs) {
|
||||||
|
this.threadIDs = threadIDs;
|
||||||
this.selectionInfo = selectionInfo;
|
this.selectionInfo = selectionInfo;
|
||||||
refresh(true);
|
refresh(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a list of Keys (BlackboardArtifact) for only messages for the
|
|
||||||
* currently selected accounts
|
|
||||||
*
|
|
||||||
* @param list List of BlackboardArtifact to populate
|
|
||||||
*
|
|
||||||
* @return True on success
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||||
CommunicationsManager communicationManager;
|
CommunicationsManager communicationManager;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
|
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
|
||||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
@ -87,19 +86,37 @@ final class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact> {
|
|||||||
final Set<Content> relationshipSources;
|
final Set<Content> relationshipSources;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter());
|
|
||||||
|
|
||||||
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
|
relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter());
|
||||||
|
for(Content content: relationshipSources) {
|
||||||
|
if( !(content instanceof BlackboardArtifact)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
BlackboardArtifact bba = (BlackboardArtifact) content;
|
BlackboardArtifact bba = (BlackboardArtifact) content;
|
||||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
|
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
|
||||||
|
|
||||||
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
|
if (fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
|
||||||
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
|
&& fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
|
||||||
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
|
&& fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want all artifacts that do not have "threadIDs" to appear as one thread in the UI
|
||||||
|
// To achive this assign any artifact that does not have a threadID
|
||||||
|
// the "UNTHREADED_ID"
|
||||||
|
String artifactThreadID = MessageNode.UNTHREADED_ID;
|
||||||
|
BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID));
|
||||||
|
|
||||||
|
if(attribute != null) {
|
||||||
|
artifactThreadID = attribute.getValueString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(threadIDs == null || threadIDs.contains(artifactThreadID)) {
|
||||||
list.add(bba);
|
list.add(bba);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
}
|
||||||
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
|
||||||
@ -110,6 +127,7 @@ final class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(BlackboardArtifact key) {
|
protected Node createNodeForKey(BlackboardArtifact key) {
|
||||||
return new MessageNode(key);
|
return new MessageNode(key, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
@ -11,33 +11,23 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,3,13,0,0,2,103"/>
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Container class="javax.swing.JSplitPane" name="splitPane">
|
<Container class="javax.swing.JSplitPane" name="splitPane">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="orientation" type="int" value="0"/>
|
<Property name="orientation" type="int" value="0"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
|
<BorderConstraints direction="Center"/>
|
||||||
</Constraint>
|
</Constraint>
|
||||||
</Constraints>
|
</Constraints>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
|
|
||||||
<AuxValues>
|
|
||||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
|
|
||||||
</AuxValues>
|
|
||||||
<Constraints>
|
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
|
||||||
<JSplitPaneConstraints position="bottom"/>
|
|
||||||
</Constraint>
|
|
||||||
</Constraints>
|
|
||||||
</Component>
|
|
||||||
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="outlineViewPanel">
|
<Component class="org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel" name="outlineViewPanel">
|
||||||
<Constraints>
|
<Constraints>
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||||
@ -45,6 +35,16 @@
|
|||||||
</Constraint>
|
</Constraint>
|
||||||
</Constraints>
|
</Constraints>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="messageContentViewer">
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
|
||||||
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||||
|
<JSplitPaneConstraints position="right"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obt ain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
@ -22,57 +22,38 @@ import java.awt.Component;
|
|||||||
import java.awt.KeyboardFocusManager;
|
import java.awt.KeyboardFocusManager;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import javax.swing.JPanel;
|
|
||||||
import static javax.swing.SwingUtilities.isDescendingFrom;
|
import static javax.swing.SwingUtilities.isDescendingFrom;
|
||||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||||
import org.netbeans.swing.outline.Outline;
|
import org.netbeans.swing.outline.Outline;
|
||||||
import org.openide.explorer.ExplorerManager;
|
import org.openide.explorer.ExplorerManager;
|
||||||
import static org.openide.explorer.ExplorerUtils.createLookup;
|
import static org.openide.explorer.ExplorerUtils.createLookup;
|
||||||
import org.openide.nodes.AbstractNode;
|
import org.openide.nodes.AbstractNode;
|
||||||
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.nodes.NodeAdapter;
|
|
||||||
import org.openide.nodes.NodeMemberEvent;
|
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle.Messages;
|
|
||||||
import org.openide.util.lookup.ServiceProvider;
|
|
||||||
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
|
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
|
||||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||||
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visualation for the messages of the currently selected accounts.
|
*
|
||||||
|
* General Purpose class for panels that need OutlineView of message nodes at
|
||||||
|
* the top with a MessageContentViewer at the bottom.
|
||||||
*/
|
*/
|
||||||
@ServiceProvider(service = RelationshipsViewer.class)
|
public class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider {
|
||||||
public final class MessagesViewer extends JPanel implements RelationshipsViewer {
|
|
||||||
|
|
||||||
private final Outline outline;
|
private final Outline outline;
|
||||||
private final ModifiableProxyLookup proxyLookup;
|
private final ModifiableProxyLookup proxyLookup;
|
||||||
private final PropertyChangeListener focusPropertyListener;
|
private final PropertyChangeListener focusPropertyListener;
|
||||||
private final MessagesChildNodeFactory nodeFactory;
|
|
||||||
|
|
||||||
@Messages({
|
|
||||||
"MessageViewer_tabTitle=Messages",
|
|
||||||
"MessageViewer_columnHeader_From=From",
|
|
||||||
"MessageViewer_columnHeader_To=To",
|
|
||||||
"MessageViewer_columnHeader_Date=Date",
|
|
||||||
"MessageViewer_columnHeader_Subject=Subject",
|
|
||||||
"MessageViewer_columnHeader_Attms=Attachments",
|
|
||||||
"MessageViewer_no_messages=<No messages found for selected account>"
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visualation for the messages of the currently selected accounts.
|
* Creates new form MessagesPanel
|
||||||
*/
|
*/
|
||||||
public MessagesViewer() {
|
public MessagesPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
splitPane.setResizeWeight(0.5);
|
|
||||||
|
|
||||||
outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages());
|
|
||||||
|
|
||||||
proxyLookup = new ModifiableProxyLookup(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
|
proxyLookup = new ModifiableProxyLookup(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
|
||||||
nodeFactory = new MessagesChildNodeFactory(null);
|
|
||||||
|
|
||||||
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
|
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
|
||||||
// explaination of focusPropertyListener
|
// explaination of focusPropertyListener
|
||||||
@ -83,10 +64,10 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
|||||||
if (newFocusOwner == null) {
|
if (newFocusOwner == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isDescendingFrom(newFocusOwner, contentViewer)) {
|
if (isDescendingFrom(newFocusOwner, messageContentViewer)) {
|
||||||
//if the focus owner is within the MessageContentViewer (the attachments table)
|
//if the focus owner is within the MessageContentViewer (the attachments table)
|
||||||
proxyLookup.setNewLookups(createLookup(((MessageDataContent) contentViewer).getExplorerManager(), getActionMap()));
|
proxyLookup.setNewLookups(createLookup(((MessageDataContent) messageContentViewer).getExplorerManager(), getActionMap()));
|
||||||
} else if (isDescendingFrom(newFocusOwner, MessagesViewer.this)) {
|
} else if (isDescendingFrom(newFocusOwner, MessagesPanel.this)) {
|
||||||
//... or if it is within the Results table.
|
//... or if it is within the Results table.
|
||||||
proxyLookup.setNewLookups(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
|
proxyLookup.setNewLookups(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
|
||||||
|
|
||||||
@ -110,52 +91,22 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
|||||||
final Node[] nodes = outlineViewPanel.getExplorerManager().getSelectedNodes();
|
final Node[] nodes = outlineViewPanel.getExplorerManager().getSelectedNodes();
|
||||||
|
|
||||||
if (nodes != null && nodes.length == 1) {
|
if (nodes != null && nodes.length == 1) {
|
||||||
contentViewer.setNode(nodes[0]);
|
messageContentViewer.setNode(nodes[0]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
contentViewer.setNode(null);
|
messageContentViewer.setNode(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
outlineViewPanel.getExplorerManager().setRootContext(
|
splitPane.setResizeWeight(0.5);
|
||||||
new TableFilterNode(
|
splitPane.setDividerLocation(0.5);
|
||||||
new DataResultFilterNode(
|
|
||||||
new AbstractNode(
|
|
||||||
Children.create(nodeFactory, true)),
|
|
||||||
outlineViewPanel.getExplorerManager()),
|
|
||||||
true));
|
|
||||||
|
|
||||||
// When a new set of nodes are added to the OutlineView the childrenAdded
|
|
||||||
// seems to be fired before the childrenRemoved.
|
|
||||||
outlineViewPanel.getExplorerManager().getRootContext().addNodeListener(new NodeAdapter() {
|
|
||||||
@Override
|
|
||||||
public void childrenAdded(NodeMemberEvent nme) {
|
|
||||||
updateOutlineViewPanel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void childrenRemoved(NodeMemberEvent nme) {
|
|
||||||
updateOutlineViewPanel();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
outlineViewPanel.setTableColumnsWidth(5,10,10,15,50,10);
|
outlineViewPanel.setTableColumnsWidth(5,10,10,15,50,10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public MessagesPanel(ChildFactory<?> nodeFactory) {
|
||||||
public String getDisplayName() {
|
this();
|
||||||
return Bundle.MessageViewer_tabTitle();
|
setChildFactory(nodeFactory);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JPanel getPanel() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSelectionInfo(SelectionInfo info) {
|
|
||||||
nodeFactory.refresh(info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -178,13 +129,13 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
|||||||
.removePropertyChangeListener("focusOwner", focusPropertyListener);
|
.removePropertyChangeListener("focusOwner", focusPropertyListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOutlineViewPanel() {
|
final void setChildFactory(ChildFactory<?> nodeFactory) {
|
||||||
int nodeCount = outlineViewPanel.getExplorerManager().getRootContext().getChildren().getNodesCount();
|
outlineViewPanel.getExplorerManager().setRootContext(
|
||||||
if(nodeCount == 0) {
|
new TableFilterNode(
|
||||||
outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages());
|
new DataResultFilterNode(
|
||||||
} else {
|
new AbstractNode(
|
||||||
outlineViewPanel.showOutlineView();
|
Children.create(nodeFactory, true)),
|
||||||
}
|
outlineViewPanel.getExplorerManager()),true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -195,31 +146,23 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
java.awt.GridBagConstraints gridBagConstraints;
|
|
||||||
|
|
||||||
splitPane = new javax.swing.JSplitPane();
|
splitPane = new javax.swing.JSplitPane();
|
||||||
contentViewer = new MessageDataContent();
|
|
||||||
outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
outlineViewPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
||||||
|
messageContentViewer = new MessageDataContent();
|
||||||
|
|
||||||
setLayout(new java.awt.GridBagLayout());
|
setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||||
splitPane.setBottomComponent(contentViewer);
|
|
||||||
splitPane.setLeftComponent(outlineViewPanel);
|
splitPane.setLeftComponent(outlineViewPanel);
|
||||||
|
splitPane.setRightComponent(messageContentViewer);
|
||||||
|
|
||||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
add(splitPane, java.awt.BorderLayout.CENTER);
|
||||||
gridBagConstraints.gridx = 0;
|
|
||||||
gridBagConstraints.gridy = 0;
|
|
||||||
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
|
||||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
|
||||||
gridBagConstraints.weightx = 1.0;
|
|
||||||
gridBagConstraints.weighty = 1.0;
|
|
||||||
add(splitPane, gridBagConstraints);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
|
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer messageContentViewer;
|
||||||
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;
|
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;
|
||||||
private javax.swing.JSplitPane splitPane;
|
private javax.swing.JSplitPane splitPane;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
@ -1,9 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
<Properties>
|
|
||||||
<Property name="enabled" type="boolean" value="false"/>
|
|
||||||
</Properties>
|
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
@ -23,12 +20,6 @@
|
|||||||
</Layout>
|
</Layout>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
|
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
|
||||||
<Properties>
|
|
||||||
<Property name="horizontalScrollBarPolicy" type="int" value="32"/>
|
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[300, 400]"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
<Constraints>
|
<Constraints>
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
|
||||||
<CardConstraints cardName="outlineCard"/>
|
<CardConstraints cardName="outlineCard"/>
|
||||||
|
@ -101,6 +101,15 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana
|
|||||||
outlineView.setEnabled(enabled);
|
outlineView.setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the width of the columns of the OutlineView based on the passed in
|
||||||
|
* list of percentages. There should be on double value for each column
|
||||||
|
* in the OutlineView.
|
||||||
|
*
|
||||||
|
* @param percentages A series of double percentages values representing
|
||||||
|
* what percent of the total width of the table each
|
||||||
|
* column should have.
|
||||||
|
*/
|
||||||
public void setTableColumnsWidth(double... percentages) {
|
public void setTableColumnsWidth(double... percentages) {
|
||||||
JTable table = outlineView.getOutline();
|
JTable table = outlineView.getOutline();
|
||||||
double total = 0;
|
double total = 0;
|
||||||
@ -127,11 +136,7 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana
|
|||||||
messagePanel = new javax.swing.JPanel();
|
messagePanel = new javax.swing.JPanel();
|
||||||
messageLabel = new javax.swing.JLabel();
|
messageLabel = new javax.swing.JLabel();
|
||||||
|
|
||||||
setEnabled(false);
|
|
||||||
setLayout(new java.awt.CardLayout(5, 5));
|
setLayout(new java.awt.CardLayout(5, 5));
|
||||||
|
|
||||||
outlineView.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
|
|
||||||
outlineView.setPreferredSize(new java.awt.Dimension(300, 400));
|
|
||||||
add(outlineView, "outlineCard");
|
add(outlineView, "outlineCard");
|
||||||
|
|
||||||
messagePanel.setLayout(new java.awt.BorderLayout());
|
messagePanel.setLayout(new java.awt.BorderLayout());
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||||
@ -22,7 +21,7 @@
|
|||||||
</Events>
|
</Events>
|
||||||
<Constraints>
|
<Constraints>
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="1" insetsLeft="1" insetsBottom="1" insetsRight="1" anchor="18" weightX="1.0" weightY="1.0"/>
|
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||||
</Constraint>
|
</Constraint>
|
||||||
</Constraints>
|
</Constraints>
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
|
|||||||
|
|
||||||
private SelectionInfo currentSelection;
|
private SelectionInfo currentSelection;
|
||||||
|
|
||||||
private final MessagesViewer messagesViewer;
|
private final MessageViewer messagesViewer;
|
||||||
private final ContactsViewer contactsViewer;
|
private final ContactsViewer contactsViewer;
|
||||||
private final SummaryViewer summaryViewer;
|
private final SummaryViewer summaryViewer;
|
||||||
private final MediaViewer mediaViewer;
|
private final MediaViewer mediaViewer;
|
||||||
@ -42,15 +42,14 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
|
|||||||
* Creates new form RelationshipBrowser
|
* Creates new form RelationshipBrowser
|
||||||
*/
|
*/
|
||||||
public RelationshipBrowser() {
|
public RelationshipBrowser() {
|
||||||
messagesViewer = new MessagesViewer();
|
initComponents();
|
||||||
|
messagesViewer = new MessageViewer();
|
||||||
contactsViewer = new ContactsViewer();
|
contactsViewer = new ContactsViewer();
|
||||||
summaryViewer = new SummaryViewer();
|
summaryViewer = new SummaryViewer();
|
||||||
mediaViewer = new MediaViewer();
|
mediaViewer = new MediaViewer();
|
||||||
|
|
||||||
proxyLookup = new ModifiableProxyLookup(messagesViewer.getLookup());
|
proxyLookup = new ModifiableProxyLookup(messagesViewer.getLookup());
|
||||||
|
|
||||||
initComponents();
|
|
||||||
|
|
||||||
tabPane.add(summaryViewer.getDisplayName(), summaryViewer);
|
tabPane.add(summaryViewer.getDisplayName(), summaryViewer);
|
||||||
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
|
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
|
||||||
tabPane.add(contactsViewer.getDisplayName(), contactsViewer);
|
tabPane.add(contactsViewer.getDisplayName(), contactsViewer);
|
||||||
@ -59,7 +58,7 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of currentSelection and passes the SelectionInfo onto the
|
* Sets the value of currentSelection and passes the SelectionInfo onto the
|
||||||
* currently selected or visible tab.
|
* currently selected\visible tab.
|
||||||
*
|
*
|
||||||
* @param info Currently selected account nodes
|
* @param info Currently selected account nodes
|
||||||
*/
|
*/
|
||||||
@ -94,7 +93,6 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
|
|||||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||||
gridBagConstraints.weightx = 1.0;
|
gridBagConstraints.weightx = 1.0;
|
||||||
gridBagConstraints.weighty = 1.0;
|
gridBagConstraints.weighty = 1.0;
|
||||||
gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
|
|
||||||
add(tabPane, gridBagConstraints);
|
add(tabPane, gridBagConstraints);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 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.communications.relationships;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.Action;
|
||||||
|
import org.openide.nodes.AbstractNode;
|
||||||
|
import org.openide.nodes.ChildFactory;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
|
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ChildFactory that creates createKeys and nodes from a given selectionInfo for
|
||||||
|
* only emails, call logs and messages.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
final class ThreadChildNodeFactory extends ChildFactory<BlackboardArtifact> {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ThreadChildNodeFactory.class.getName());
|
||||||
|
|
||||||
|
private SelectionInfo selectionInfo;
|
||||||
|
|
||||||
|
private final Action preferredAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new ThreadChildNodeFactory from the currently selectionInfo
|
||||||
|
*
|
||||||
|
* @param preferredAction SelectionInfo object for the currently selected
|
||||||
|
* accounts
|
||||||
|
*/
|
||||||
|
|
||||||
|
ThreadChildNodeFactory(Action preferredAction) {
|
||||||
|
this.preferredAction = preferredAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the current instance of selectionInfo and calls the refresh method.
|
||||||
|
*
|
||||||
|
* @param selectionInfo New instance of the currently selected accounts
|
||||||
|
*/
|
||||||
|
public void refresh(SelectionInfo selectionInfo) {
|
||||||
|
this.selectionInfo = selectionInfo;
|
||||||
|
refresh(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a list of Keys (BlackboardArtifact) for only messages for the
|
||||||
|
* currently selected accounts.
|
||||||
|
*
|
||||||
|
* @param list List of BlackboardArtifact to populate
|
||||||
|
*
|
||||||
|
* @return True on success
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||||
|
CommunicationsManager communicationManager;
|
||||||
|
try {
|
||||||
|
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selectionInfo == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<Content> relationshipSources;
|
||||||
|
|
||||||
|
try {
|
||||||
|
relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter());
|
||||||
|
|
||||||
|
createRootMessageKeys(list, relationshipSources) ;
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds only BlackboardArtifact objects to the list where are the earliest
|
||||||
|
* message in a message thread (based on threadID). If there are "unthreaded"
|
||||||
|
* messages (messages that do not have a threadID) one representitive artifact
|
||||||
|
* will be added to the list and dealt with a node creation time.
|
||||||
|
*
|
||||||
|
* @param list List to populate with BlackboardArtifact keys
|
||||||
|
* @param relationshipSources Set of Content objects
|
||||||
|
* @return True on success
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
private boolean createRootMessageKeys(List<BlackboardArtifact> list, Set<Content> relationshipSources) throws TskCoreException{
|
||||||
|
Map<String, BlackboardArtifact> rootMessageMap = new HashMap<>();
|
||||||
|
for(Content content: relationshipSources) {
|
||||||
|
if(!(content instanceof BlackboardArtifact)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlackboardArtifact bba = (BlackboardArtifact) content;
|
||||||
|
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
|
||||||
|
|
||||||
|
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
|
||||||
|
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
|
||||||
|
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
|
||||||
|
|
||||||
|
// We want all artifacts that do not have "threadIDs" to appear as one thread in the UI
|
||||||
|
// To achive this assign any artifact that does not have a threadID
|
||||||
|
// the "UNTHREADED_ID"
|
||||||
|
String threadID = MessageNode.UNTHREADED_ID;
|
||||||
|
BlackboardAttribute attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID));
|
||||||
|
|
||||||
|
if(attribute != null) {
|
||||||
|
threadID = attribute.getValueString();
|
||||||
|
}
|
||||||
|
|
||||||
|
BlackboardArtifact tableArtifact = rootMessageMap.get(threadID);
|
||||||
|
if(tableArtifact == null) {
|
||||||
|
rootMessageMap.put(threadID, bba);
|
||||||
|
} else {
|
||||||
|
// Get the date of the message
|
||||||
|
BlackboardAttribute tableAttribute = tableArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT));
|
||||||
|
attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT));
|
||||||
|
|
||||||
|
// put the earliest message into the table
|
||||||
|
if(tableAttribute != null
|
||||||
|
&& attribute != null
|
||||||
|
&& tableAttribute.getValueLong() > attribute.getValueLong()) {
|
||||||
|
rootMessageMap.put(threadID, bba);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(BlackboardArtifact bba: rootMessageMap.values()) {
|
||||||
|
list.add(bba);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node createNodeForKey(BlackboardArtifact bba) {
|
||||||
|
BlackboardAttribute attribute = null;
|
||||||
|
try {
|
||||||
|
attribute = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID));
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, String.format("Unable to get threadID for artifact: %s", bba.getName()), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attribute != null) {
|
||||||
|
return new ThreadNode(bba, attribute.getValueString(), preferredAction);
|
||||||
|
} else {
|
||||||
|
// Only one of these should occur.
|
||||||
|
return new UnthreadedNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An this node represents the "unthreaded" thread.
|
||||||
|
*/
|
||||||
|
final class UnthreadedNode extends AbstractNode {
|
||||||
|
/**
|
||||||
|
* Construct an instance of UnthreadNode.
|
||||||
|
*/
|
||||||
|
UnthreadedNode() {
|
||||||
|
super(Children.LEAF);
|
||||||
|
setDisplayName("Unthreaded");
|
||||||
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/unthreaded.png" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
Sheet sheet = super.createSheet();
|
||||||
|
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||||
|
if (sheetSet == null) {
|
||||||
|
sheetSet = Sheet.createPropertiesSet();
|
||||||
|
sheet.put(sheetSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give this node a threadID of "UNTHEADED_ID"
|
||||||
|
sheetSet.put(new NodeProperty<>("ThreadID", "ThreadID","",MessageNode.UNTHREADED_ID));
|
||||||
|
|
||||||
|
return sheet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java
Executable file
60
Core/src/org/sleuthkit/autopsy/communications/relationships/ThreadNode.java
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 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.communications.relationships;
|
||||||
|
|
||||||
|
import javax.swing.Action;
|
||||||
|
import org.openide.nodes.AbstractNode;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An AbstractNode subclass which wraps a MessagNode object. Doing this allows
|
||||||
|
* for the reuse of the createSheet and other function from MessageNode, but
|
||||||
|
* also some customizing of how a ThreadNode is shown.
|
||||||
|
*/
|
||||||
|
final class ThreadNode extends AbstractNode{
|
||||||
|
|
||||||
|
final private MessageNode messageNode;
|
||||||
|
|
||||||
|
ThreadNode(BlackboardArtifact artifact, String threadID, Action preferredAction) {
|
||||||
|
super(Children.LEAF);
|
||||||
|
messageNode = new MessageNode(artifact, threadID, preferredAction);
|
||||||
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/communications/images/threaded.png" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
return messageNode.createSheet();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getThreadID() {
|
||||||
|
return messageNode.getThreadID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action getPreferredAction() {
|
||||||
|
return messageNode.getPreferredAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return messageNode.getDisplayName();
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,6 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyChangeSupport;
|
import java.beans.PropertyChangeSupport;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -78,7 +77,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
|||||||
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.ContentViewerTag;
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.ContentViewerTag;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.SerializationException;
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.SerializationException;
|
||||||
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtility;
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtil;
|
||||||
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagControls;
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagControls;
|
||||||
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion;
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion;
|
||||||
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagCreator;
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagCreator;
|
||||||
@ -876,13 +875,14 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
|||||||
.map(cvTag -> cvTag.getDetails()).collect(Collectors.toList());
|
.map(cvTag -> cvTag.getDetails()).collect(Collectors.toList());
|
||||||
|
|
||||||
//Apply tags to image and write to file
|
//Apply tags to image and write to file
|
||||||
BufferedImage pngImage = ImageTagsUtility.writeTags(file, regions, "png");
|
BufferedImage taggedImage = ImageTagsUtil.getImageWithTags(file, regions);
|
||||||
Path output = Paths.get(exportChooser.getSelectedFile().getPath(),
|
Path output = Paths.get(exportChooser.getSelectedFile().getPath(),
|
||||||
FilenameUtils.getBaseName(file.getName()) + "-with_tags.png"); //NON-NLS
|
FilenameUtils.getBaseName(file.getName()) + "-with_tags.png"); //NON-NLS
|
||||||
ImageIO.write(pngImage, "png", output.toFile());
|
ImageIO.write(taggedImage, "png", output.toFile());
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport());
|
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_successfulExport());
|
||||||
} catch (TskCoreException | NoCurrentCaseException | IOException ex) {
|
} catch (Exception ex) { //Runtime exceptions may spill out of ImageTagsUtil from JavaFX.
|
||||||
|
//This ensures we (devs and users) have something when it doesn't work.
|
||||||
LOGGER.log(Level.WARNING, "Unable to export tagged image to disk", ex); //NON-NLS
|
LOGGER.log(Level.WARNING, "Unable to export tagged image to disk", ex); //NON-NLS
|
||||||
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_unsuccessfulExport());
|
JOptionPane.showMessageDialog(null, Bundle.MediaViewImagePanel_unsuccessfulExport());
|
||||||
}
|
}
|
||||||
|
239
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtil.java
Executable file
239
Core/src/org/sleuthkit/autopsy/contentviewers/imagetagging/ImageTagsUtil.java
Executable file
@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2019 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.contentviewers.imagetagging;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
|
import javafx.embed.swing.SwingFXUtils;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import org.opencv.core.Core;
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.core.MatOfByte;
|
||||||
|
import org.opencv.core.Point;
|
||||||
|
import org.opencv.core.Scalar;
|
||||||
|
import org.opencv.core.Size;
|
||||||
|
import org.opencv.highgui.Highgui;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility for drawing rectangles on image files.
|
||||||
|
*/
|
||||||
|
public final class ImageTagsUtil {
|
||||||
|
|
||||||
|
//String constant for writing PNG in ImageIO
|
||||||
|
private final static String AWT_PNG = "png";
|
||||||
|
|
||||||
|
//String constant for encoding PNG in OpenCV
|
||||||
|
private final static String OPENCV_PNG = ".png";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an image with tags applied.
|
||||||
|
*
|
||||||
|
* @param file Source image.
|
||||||
|
* @param tagRegions Tags to apply.
|
||||||
|
* @return Tagged image.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* @throws InterruptedException Calling thread was interrupted
|
||||||
|
* @throws ExecutionException Error while reading image from AbstractFile
|
||||||
|
*/
|
||||||
|
public static BufferedImage getImageWithTags(AbstractFile file,
|
||||||
|
Collection<ImageTagRegion> tagRegions) throws IOException, InterruptedException, ExecutionException {
|
||||||
|
|
||||||
|
//The raw image in OpenCV terms
|
||||||
|
Mat sourceImage = getImageMatFromFile(file);
|
||||||
|
//Image with tags in OpenCV terms
|
||||||
|
MatOfByte taggedMatrix = getTaggedImageMatrix(sourceImage, tagRegions);
|
||||||
|
|
||||||
|
try (ByteArrayInputStream taggedStream = new ByteArrayInputStream(taggedMatrix.toArray())) {
|
||||||
|
return ImageIO.read(taggedStream);
|
||||||
|
} finally {
|
||||||
|
sourceImage.release();
|
||||||
|
taggedMatrix.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the image from file.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws ExecutionException
|
||||||
|
*/
|
||||||
|
private static BufferedImage getImageFromFile(AbstractFile file) throws IOException, InterruptedException, ExecutionException {
|
||||||
|
if (ImageUtils.isGIF(file)) {
|
||||||
|
//Grab the first frame.
|
||||||
|
try (BufferedInputStream bufferedReadContentStream =
|
||||||
|
new BufferedInputStream(new ReadContentInputStream(file))) {
|
||||||
|
return ImageIO.read(bufferedReadContentStream);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Otherwise, read the full image.
|
||||||
|
Task<Image> readImageTask = ImageUtils.newReadImageTask(file);
|
||||||
|
readImageTask.run();
|
||||||
|
Image fxResult = readImageTask.get();
|
||||||
|
return SwingFXUtils.fromFXImage(fxResult, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the image and converts it into an OpenCV equivalent.
|
||||||
|
*
|
||||||
|
* @param file Image to read
|
||||||
|
* @return raw image bytes
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* @throws InterruptedException Calling thread was interrupted.
|
||||||
|
* @throws ExecutionException Error while reading image from AbstractFile
|
||||||
|
*/
|
||||||
|
private static Mat getImageMatFromFile(AbstractFile file) throws InterruptedException, ExecutionException, IOException {
|
||||||
|
//Get image from file
|
||||||
|
BufferedImage buffImage = getImageFromFile(file);
|
||||||
|
|
||||||
|
//Convert it to OpenCV Mat.
|
||||||
|
try (ByteArrayOutputStream outStream = new ByteArrayOutputStream()) {
|
||||||
|
ImageIO.write(buffImage, AWT_PNG, outStream);
|
||||||
|
|
||||||
|
byte[] imageBytes = outStream.toByteArray();
|
||||||
|
MatOfByte rawSourceBytes = new MatOfByte(imageBytes);
|
||||||
|
Mat sourceImage = Highgui.imdecode(rawSourceBytes, Highgui.IMREAD_COLOR);
|
||||||
|
rawSourceBytes.release();
|
||||||
|
|
||||||
|
return sourceImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds tags to an image matrix.
|
||||||
|
*
|
||||||
|
* @param sourceImage
|
||||||
|
* @param tagRegions
|
||||||
|
* @param outputEncoding
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static MatOfByte getTaggedImageMatrix(Mat sourceImage, Collection<ImageTagRegion> tagRegions) {
|
||||||
|
|
||||||
|
//Apply all tags to source image
|
||||||
|
for (ImageTagRegion region : tagRegions) {
|
||||||
|
Point topLeft = new Point(region.getX(), region.getY());
|
||||||
|
Point bottomRight = new Point(topLeft.x + region.getWidth(),
|
||||||
|
topLeft.y + region.getHeight());
|
||||||
|
//Red
|
||||||
|
Scalar rectangleBorderColor = new Scalar(0, 0, 255);
|
||||||
|
|
||||||
|
int rectangleBorderWidth = (int) Math.rint(region.getStrokeThickness());
|
||||||
|
|
||||||
|
Core.rectangle(sourceImage, topLeft, bottomRight,
|
||||||
|
rectangleBorderColor, rectangleBorderWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
MatOfByte taggedMatrix = new MatOfByte();
|
||||||
|
Highgui.imencode(OPENCV_PNG, sourceImage, taggedMatrix);
|
||||||
|
|
||||||
|
return taggedMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a thumbnail with tags applied.
|
||||||
|
*
|
||||||
|
* @param file Input file to apply tags & produce thumbnail from
|
||||||
|
* @param tagRegions Tags to apply
|
||||||
|
* @param iconSize Size of the output thumbnail
|
||||||
|
* @return BufferedImage Thumbnail image
|
||||||
|
*
|
||||||
|
* @throws InterruptedException Calling thread was interrupted.
|
||||||
|
* @throws ExecutionException Error while reading image from file.
|
||||||
|
*/
|
||||||
|
public static BufferedImage getThumbnailWithTags(AbstractFile file, Collection<ImageTagRegion> tagRegions,
|
||||||
|
IconSize iconSize) throws IOException, InterruptedException, ExecutionException {
|
||||||
|
|
||||||
|
//Raw image
|
||||||
|
Mat sourceImage = getImageMatFromFile(file);
|
||||||
|
//Full size image with tags
|
||||||
|
MatOfByte taggedMatrix = getTaggedImageMatrix(sourceImage, tagRegions);
|
||||||
|
//Resized to produce thumbnail
|
||||||
|
MatOfByte thumbnailMatrix = getResizedMatrix(taggedMatrix, iconSize);
|
||||||
|
|
||||||
|
try (ByteArrayInputStream thumbnailStream = new ByteArrayInputStream(thumbnailMatrix.toArray())) {
|
||||||
|
return ImageIO.read(thumbnailStream);
|
||||||
|
} finally {
|
||||||
|
sourceImage.release();
|
||||||
|
taggedMatrix.release();
|
||||||
|
thumbnailMatrix.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizes the image matrix.
|
||||||
|
*
|
||||||
|
* @param taggedMatrix Image to resize.
|
||||||
|
* @param size Size of thumbnail.
|
||||||
|
*
|
||||||
|
* @return A new resized image matrix.
|
||||||
|
*/
|
||||||
|
private static MatOfByte getResizedMatrix(MatOfByte taggedMatrix, IconSize size) {
|
||||||
|
Size resizeDimensions = new Size(size.getSize(), size.getSize());
|
||||||
|
Mat taggedImage = Highgui.imdecode(taggedMatrix, Highgui.IMREAD_COLOR);
|
||||||
|
|
||||||
|
Mat thumbnailImage = new Mat();
|
||||||
|
Imgproc.resize(taggedImage, thumbnailImage, resizeDimensions);
|
||||||
|
|
||||||
|
MatOfByte thumbnailMatrix = new MatOfByte();
|
||||||
|
Highgui.imencode(OPENCV_PNG, thumbnailImage, thumbnailMatrix);
|
||||||
|
|
||||||
|
thumbnailImage.release();
|
||||||
|
taggedImage.release();
|
||||||
|
|
||||||
|
return thumbnailMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageTagsUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sizes for thumbnails
|
||||||
|
*/
|
||||||
|
public enum IconSize {
|
||||||
|
SMALL(50),
|
||||||
|
MEDIUM(100),
|
||||||
|
LARGE(200);
|
||||||
|
|
||||||
|
private final int SIZE;
|
||||||
|
|
||||||
|
IconSize(int size) {
|
||||||
|
this.SIZE = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,141 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2019 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.contentviewers.imagetagging;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import org.opencv.core.Core;
|
|
||||||
import org.opencv.core.Mat;
|
|
||||||
import org.opencv.core.MatOfByte;
|
|
||||||
import org.opencv.core.MatOfInt;
|
|
||||||
import org.opencv.core.Point;
|
|
||||||
import org.opencv.core.Scalar;
|
|
||||||
import org.opencv.core.Size;
|
|
||||||
import org.opencv.highgui.Highgui;
|
|
||||||
import org.opencv.imgproc.Imgproc;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class for handling content viewer tags on images.
|
|
||||||
*/
|
|
||||||
public final class ImageTagsUtility {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sizes for thumbnails
|
|
||||||
*/
|
|
||||||
public enum IconSize {
|
|
||||||
SMALL(50),
|
|
||||||
MEDIUM(100),
|
|
||||||
LARGE(200);
|
|
||||||
|
|
||||||
private final int SIZE;
|
|
||||||
|
|
||||||
IconSize(int size) {
|
|
||||||
this.SIZE = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSize() {
|
|
||||||
return SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Embeds the tag regions into an image.
|
|
||||||
*
|
|
||||||
* @param file Base Image
|
|
||||||
* @param tagRegions Tag regions to be saved into the image
|
|
||||||
* @param outputEncoding Format of image (jpg, png, etc). See OpenCV for
|
|
||||||
* supported formats. Do not include a "."
|
|
||||||
* @return Output image as a BufferedImage
|
|
||||||
*
|
|
||||||
* @throws TskCoreException Cannot read from abstract file
|
|
||||||
* @throws IOException Could not create buffered image from OpenCV result
|
|
||||||
*/
|
|
||||||
public static BufferedImage writeTags(AbstractFile file, Collection<ImageTagRegion> tagRegions,
|
|
||||||
String outputEncoding) throws TskCoreException, IOException {
|
|
||||||
byte[] imageInMemory = new byte[(int) file.getSize()];
|
|
||||||
file.read(imageInMemory, 0, file.getSize());
|
|
||||||
Mat originalImage = Highgui.imdecode(new MatOfByte(imageInMemory), Highgui.IMREAD_UNCHANGED);
|
|
||||||
|
|
||||||
tagRegions.forEach((region) -> {
|
|
||||||
Core.rectangle(
|
|
||||||
originalImage, //Matrix obj of the image
|
|
||||||
new Point(region.getX(), region.getY()), //p1
|
|
||||||
new Point(region.getX() + region.getWidth(), region.getY() + region.getHeight()), //p2
|
|
||||||
new Scalar(0, 0, 255), //Scalar object for color
|
|
||||||
(int) Math.rint(region.getStrokeThickness())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
MatOfByte matOfByte = new MatOfByte();
|
|
||||||
MatOfInt params = new MatOfInt(Highgui.IMWRITE_JPEG_QUALITY, 100);
|
|
||||||
Highgui.imencode("." + outputEncoding, originalImage, matOfByte, params);
|
|
||||||
|
|
||||||
try (ByteArrayInputStream imageStream = new ByteArrayInputStream(matOfByte.toArray())) {
|
|
||||||
BufferedImage result = ImageIO.read(imageStream);
|
|
||||||
originalImage.release();
|
|
||||||
matOfByte.release();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a thumbnail version of the image with tags applied.
|
|
||||||
*
|
|
||||||
* @param file Input file to apply tags & produce thumbnail from
|
|
||||||
* @param tagRegions Tags to apply
|
|
||||||
* @param iconSize Size of the output thumbnail
|
|
||||||
* @param outputEncoding Format of thumbnail (jpg, png, etc). See OpenCV for
|
|
||||||
* supported formats. Do not include a "."
|
|
||||||
* @return BufferedImage representing the thumbnail
|
|
||||||
*
|
|
||||||
* @throws TskCoreException Could not read from file
|
|
||||||
* @throws IOException Could not create buffered image from OpenCV result
|
|
||||||
*/
|
|
||||||
public static BufferedImage makeThumbnail(AbstractFile file, Collection<ImageTagRegion> tagRegions,
|
|
||||||
IconSize iconSize, String outputEncoding) throws TskCoreException, IOException {
|
|
||||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
|
||||||
BufferedImage result = writeTags(file, tagRegions, outputEncoding);
|
|
||||||
ImageIO.write(result, outputEncoding, baos);
|
|
||||||
Mat markedUpImage = Highgui.imdecode(new MatOfByte(baos.toByteArray()), Highgui.IMREAD_UNCHANGED);
|
|
||||||
Mat thumbnail = new Mat();
|
|
||||||
Size resize = new Size(iconSize.getSize(), iconSize.getSize());
|
|
||||||
|
|
||||||
Imgproc.resize(markedUpImage, thumbnail, resize);
|
|
||||||
MatOfByte matOfByte = new MatOfByte();
|
|
||||||
Highgui.imencode("." + outputEncoding, thumbnail, matOfByte);
|
|
||||||
|
|
||||||
try (ByteArrayInputStream thumbnailStream = new ByteArrayInputStream(matOfByte.toArray())) {
|
|
||||||
BufferedImage thumbnailImage = ImageIO.read(thumbnailStream);
|
|
||||||
thumbnail.release();
|
|
||||||
matOfByte.release();
|
|
||||||
markedUpImage.release();
|
|
||||||
return thumbnailImage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ImageTagsUtility() {
|
|
||||||
}
|
|
||||||
}
|
|
@ -302,6 +302,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
try {
|
try {
|
||||||
if (rootNode != null) {
|
if (rootNode != null) {
|
||||||
|
this.rootNode = rootNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if we have previously created a paging support
|
* Check to see if we have previously created a paging support
|
||||||
* class for this node.
|
* class for this node.
|
||||||
@ -364,8 +366,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
* case database round trips.
|
* case database round trips.
|
||||||
*/
|
*/
|
||||||
if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) {
|
if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) {
|
||||||
this.rootNode = rootNode;
|
|
||||||
|
|
||||||
this.getExplorerManager().setRootContext(this.rootNode);
|
this.getExplorerManager().setRootContext(this.rootNode);
|
||||||
setupTable();
|
setupTable();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1845,7 +1845,8 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
return ICON_BASE_PATH + "WhatsApp.png";
|
return ICON_BASE_PATH + "WhatsApp.png";
|
||||||
} else {
|
} else {
|
||||||
//there could be a default icon instead...
|
//there could be a default icon instead...
|
||||||
throw new IllegalArgumentException("Unknown Account.Type: " + type.getTypeName());
|
return ICON_BASE_PATH + "face.png";
|
||||||
|
// throw new IllegalArgumentException("Unknown Account.Type: " + type.getTypeName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -490,6 +490,12 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractAction visit(BlackboardArtifactNode ban) {
|
public AbstractAction visit(BlackboardArtifactNode ban) {
|
||||||
|
|
||||||
|
Action preferredAction = ban.getPreferredAction();
|
||||||
|
if(preferredAction instanceof AbstractAction) {
|
||||||
|
return (AbstractAction) preferredAction;
|
||||||
|
}
|
||||||
|
|
||||||
BlackboardArtifact artifact = ban.getArtifact();
|
BlackboardArtifact artifact = ban.getArtifact();
|
||||||
try {
|
try {
|
||||||
if ((artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())
|
if ((artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2014-2018 Basis Technology Corp.
|
* Copyright 2014-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -286,7 +286,7 @@ public final class DataSourceIngestJob {
|
|||||||
this.addIngestModules(fileIngestModuleTemplates, IngestModuleType.FILE_LEVEL, skCase);
|
this.addIngestModules(fileIngestModuleTemplates, IngestModuleType.FILE_LEVEL, skCase);
|
||||||
this.addIngestModules(secondStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase);
|
this.addIngestModules(secondStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase);
|
||||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to add ingest modules to database.", ex);
|
logErrorMessage(Level.WARNING, "Failed to add ingest modules listing to case database", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,13 +421,13 @@ public final class DataSourceIngestJob {
|
|||||||
try {
|
try {
|
||||||
this.ingestJob = Case.getCurrentCaseThrows().getSleuthkitCase().addIngestJob(dataSource, NetworkUtils.getLocalHostName(), ingestModules, new Date(this.createTime), new Date(0), IngestJobStatusType.STARTED, "");
|
this.ingestJob = Case.getCurrentCaseThrows().getSleuthkitCase().addIngestJob(dataSource, NetworkUtils.getLocalHostName(), ingestModules, new Date(this.createTime), new Date(0), IngestJobStatusType.STARTED, "");
|
||||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to add ingest job to database.", ex);
|
logErrorMessage(Level.WARNING, "Failed to add ingest job info to case database", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
if (this.hasFirstStageDataSourceIngestPipeline() || this.hasFileIngestPipeline()) {
|
if (this.hasFirstStageDataSourceIngestPipeline() || this.hasFileIngestPipeline()) {
|
||||||
logger.log(Level.INFO, "Starting first stage analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
|
logInfoMessage("Starting first stage analysis"); //NON-NLS
|
||||||
this.startFirstStage();
|
this.startFirstStage();
|
||||||
} else if (this.hasSecondStageDataSourceIngestPipeline()) {
|
} else if (this.hasSecondStageDataSourceIngestPipeline()) {
|
||||||
logger.log(Level.INFO, "Starting second stage analysis for {0} (jobId={1}), no first stage configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS
|
logInfoMessage("Starting second stage analysis"); //NON-NLS
|
||||||
this.startSecondStage();
|
this.startSecondStage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -521,13 +521,13 @@ public final class DataSourceIngestJob {
|
|||||||
* Schedule the first stage tasks.
|
* Schedule the first stage tasks.
|
||||||
*/
|
*/
|
||||||
if (this.hasFirstStageDataSourceIngestPipeline() && this.hasFileIngestPipeline()) {
|
if (this.hasFirstStageDataSourceIngestPipeline() && this.hasFileIngestPipeline()) {
|
||||||
logger.log(Level.INFO, "Scheduling first stage data source and file level analysis tasks for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
|
logInfoMessage("Scheduling first stage data source and file level analysis tasks"); //NON-NLS
|
||||||
DataSourceIngestJob.taskScheduler.scheduleIngestTasks(this);
|
DataSourceIngestJob.taskScheduler.scheduleIngestTasks(this);
|
||||||
} else if (this.hasFirstStageDataSourceIngestPipeline()) {
|
} else if (this.hasFirstStageDataSourceIngestPipeline()) {
|
||||||
logger.log(Level.INFO, "Scheduling first stage data source level analysis tasks for {0} (jobId={1}), no file level analysis configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS
|
logInfoMessage("Scheduling first stage data source level analysis tasks"); //NON-NLS
|
||||||
DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this);
|
DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this);
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.INFO, "Scheduling file level analysis tasks for {0} (jobId={1}), no first stage data source level analysis configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS
|
logInfoMessage("Scheduling file level analysis tasks, no first stage data source level analysis configured"); //NON-NLS
|
||||||
DataSourceIngestJob.taskScheduler.scheduleFileIngestTasks(this, this.files);
|
DataSourceIngestJob.taskScheduler.scheduleFileIngestTasks(this, this.files);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -546,7 +546,7 @@ public final class DataSourceIngestJob {
|
|||||||
* Starts the second stage of this ingest job.
|
* Starts the second stage of this ingest job.
|
||||||
*/
|
*/
|
||||||
private void startSecondStage() {
|
private void startSecondStage() {
|
||||||
logger.log(Level.INFO, "Starting second stage analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
|
logInfoMessage("Starting second stage analysis"); //NON-NLS
|
||||||
this.stage = DataSourceIngestJob.Stages.SECOND;
|
this.stage = DataSourceIngestJob.Stages.SECOND;
|
||||||
if (this.doUI) {
|
if (this.doUI) {
|
||||||
this.startDataSourceIngestProgressBar();
|
this.startDataSourceIngestProgressBar();
|
||||||
@ -554,7 +554,7 @@ public final class DataSourceIngestJob {
|
|||||||
synchronized (this.dataSourceIngestPipelineLock) {
|
synchronized (this.dataSourceIngestPipelineLock) {
|
||||||
this.currentDataSourceIngestPipeline = this.secondStageDataSourceIngestPipeline;
|
this.currentDataSourceIngestPipeline = this.secondStageDataSourceIngestPipeline;
|
||||||
}
|
}
|
||||||
logger.log(Level.INFO, "Scheduling second stage data source level analysis tasks for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
|
logInfoMessage("Scheduling second stage data source level analysis tasks"); //NON-NLS
|
||||||
DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this);
|
DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,7 +643,7 @@ public final class DataSourceIngestJob {
|
|||||||
* job and starts the second stage, if appropriate.
|
* job and starts the second stage, if appropriate.
|
||||||
*/
|
*/
|
||||||
private void finishFirstStage() {
|
private void finishFirstStage() {
|
||||||
logger.log(Level.INFO, "Finished first stage analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
|
logInfoMessage("Finished first stage analysis"); //NON-NLS
|
||||||
|
|
||||||
// Shut down the file ingest pipelines. Note that no shut down is
|
// Shut down the file ingest pipelines. Note that no shut down is
|
||||||
// required for the data source ingest pipeline because data source
|
// required for the data source ingest pipeline because data source
|
||||||
@ -693,7 +693,7 @@ public final class DataSourceIngestJob {
|
|||||||
* Shuts down the ingest pipelines and progress bars for this job.
|
* Shuts down the ingest pipelines and progress bars for this job.
|
||||||
*/
|
*/
|
||||||
private void finish() {
|
private void finish() {
|
||||||
logger.log(Level.INFO, "Finished analysis for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS
|
logInfoMessage("Finished analysis"); //NON-NLS
|
||||||
this.stage = DataSourceIngestJob.Stages.FINALIZATION;
|
this.stage = DataSourceIngestJob.Stages.FINALIZATION;
|
||||||
|
|
||||||
if (this.doUI) {
|
if (this.doUI) {
|
||||||
@ -711,19 +711,19 @@ public final class DataSourceIngestJob {
|
|||||||
try {
|
try {
|
||||||
ingestJob.setIngestJobStatus(IngestJobStatusType.CANCELLED);
|
ingestJob.setIngestJobStatus(IngestJobStatusType.CANCELLED);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to set ingest status for ingest job in database.", ex);
|
logErrorMessage(Level.WARNING, "Failed to update ingest job status in case database", ex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
ingestJob.setIngestJobStatus(IngestJobStatusType.COMPLETED);
|
ingestJob.setIngestJobStatus(IngestJobStatusType.COMPLETED);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to set ingest status for ingest job in database.", ex);
|
logErrorMessage(Level.WARNING, "Failed to update ingest job status in case database", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.ingestJob.setEndDateTime(new Date());
|
this.ingestJob.setEndDateTime(new Date());
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to set end date for ingest job in database.", ex);
|
logErrorMessage(Level.WARNING, "Failed to set job end date in case database", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.parentJob.dataSourceJobFinished(this);
|
this.parentJob.dataSourceJobFinished(this);
|
||||||
@ -842,7 +842,7 @@ public final class DataSourceIngestJob {
|
|||||||
if (DataSourceIngestJob.Stages.FIRST == this.stage) {
|
if (DataSourceIngestJob.Stages.FIRST == this.stage) {
|
||||||
DataSourceIngestJob.taskScheduler.fastTrackFileIngestTasks(this, files);
|
DataSourceIngestJob.taskScheduler.fastTrackFileIngestTasks(this, files);
|
||||||
} else {
|
} else {
|
||||||
DataSourceIngestJob.logger.log(Level.SEVERE, "Adding files during second stage not supported"); //NON-NLS
|
logErrorMessage(Level.SEVERE, "Adding files to job during second stage analysis not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1066,6 +1066,39 @@ public final class DataSourceIngestJob {
|
|||||||
return this.cancellationReason;
|
return this.cancellationReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes an info message to the application log that includes the data
|
||||||
|
* source name, data source object id, and the job id.
|
||||||
|
*
|
||||||
|
* @param message The message.
|
||||||
|
*/
|
||||||
|
private void logInfoMessage(String message) {
|
||||||
|
logger.log(Level.INFO, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id)); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes an error message to the application log that includes the data
|
||||||
|
* source name, data source object id, and the job id.
|
||||||
|
*
|
||||||
|
* @param level The logging level for the message.
|
||||||
|
* @param message The message.
|
||||||
|
* @param throwable The throwable associated with the error.
|
||||||
|
*/
|
||||||
|
private void logErrorMessage(Level level, String message, Throwable throwable) {
|
||||||
|
logger.log(level, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id), throwable); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes an error message to the application log that includes the data
|
||||||
|
* source name, data source object id, and the job id.
|
||||||
|
*
|
||||||
|
* @param level The logging level for the message.
|
||||||
|
* @param message The message.
|
||||||
|
*/
|
||||||
|
private void logErrorMessage(Level level, String message) {
|
||||||
|
logger.log(level, String.format("%s (data source = %s, objId = %d, jobId = %d)", message, dataSource.getName(), dataSource.getId(), id)); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write ingest module errors to the log.
|
* Write ingest module errors to the log.
|
||||||
*
|
*
|
||||||
@ -1073,7 +1106,7 @@ public final class DataSourceIngestJob {
|
|||||||
*/
|
*/
|
||||||
private void logIngestModuleErrors(List<IngestModuleError> errors) {
|
private void logIngestModuleErrors(List<IngestModuleError> errors) {
|
||||||
for (IngestModuleError error : errors) {
|
for (IngestModuleError error : errors) {
|
||||||
DataSourceIngestJob.logger.log(Level.SEVERE, String.format("%s experienced an error analyzing %s (jobId=%d)", error.getModuleDisplayName(), dataSource.getName(), this.id), error.getThrowable()); //NON-NLS
|
logErrorMessage(Level.SEVERE, String.format("%s experienced an error during analysis", error.getModuleDisplayName()), error.getThrowable()); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2012-2018 Basis Technology Corp.
|
* Copyright 2012-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -403,10 +403,10 @@ public class IngestManager implements IngestProgressSnapshotProvider {
|
|||||||
synchronized (ingestJobsById) {
|
synchronized (ingestJobsById) {
|
||||||
ingestJobsById.put(job.getId(), job);
|
ingestJobsById.put(job.getId(), job);
|
||||||
}
|
}
|
||||||
|
IngestManager.logger.log(Level.INFO, "Starting ingest job {0}", job.getId()); //NON-NLS
|
||||||
errors = job.start();
|
errors = job.start();
|
||||||
if (errors.isEmpty()) {
|
if (errors.isEmpty()) {
|
||||||
this.fireIngestJobStarted(job.getId());
|
this.fireIngestJobStarted(job.getId());
|
||||||
IngestManager.logger.log(Level.INFO, "Ingest job {0} started", job.getId()); //NON-NLS
|
|
||||||
} else {
|
} else {
|
||||||
synchronized (ingestJobsById) {
|
synchronized (ingestJobsById) {
|
||||||
this.ingestJobsById.remove(job.getId());
|
this.ingestJobsById.remove(job.getId());
|
||||||
|
@ -135,7 +135,7 @@ final class ConfigVisualPanel1 extends JPanel {
|
|||||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||||
FileFilter filter = new FileNameExtensionFilter(Bundle.ConfigVisualPanel1_fileNameExtensionFilter(), new String[] {"json"}); // NON-NLS
|
FileFilter filter = new FileNameExtensionFilter(Bundle.ConfigVisualPanel1_fileNameExtensionFilter(), new String[] {"json"}); // NON-NLS
|
||||||
fileChooser.setFileFilter(filter);
|
fileChooser.setFileFilter(filter);
|
||||||
fileChooser.setSelectedFile(new File("config.json")); // default
|
fileChooser.setSelectedFile(new File("logical-imager-config.json")); // default
|
||||||
fileChooser.setMultiSelectionEnabled(false);
|
fileChooser.setMultiSelectionEnabled(false);
|
||||||
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
||||||
String path = fileChooser.getSelectedFile().getPath();
|
String path = fileChooser.getSelectedFile().getPath();
|
||||||
|
Binary file not shown.
@ -26,15 +26,24 @@ HashDbSearchAction.noOpenCase.errMsg=No open case available.
|
|||||||
HashDbSearchPanel.noOpenCase.errMsg=No open case available.
|
HashDbSearchPanel.noOpenCase.errMsg=No open case available.
|
||||||
HashLookupSettingsPanel.centralRepo=Central Repository
|
HashLookupSettingsPanel.centralRepo=Central Repository
|
||||||
HashLookupSettingsPanel.editable=Editable
|
HashLookupSettingsPanel.editable=Editable
|
||||||
|
HashLookupSettingsPanel.indexNsrl.text=This hash set appears to be the NSRL, it will be removed from the list.\n
|
||||||
|
HashLookupSettingsPanel.indexNsrl.title=NSRL will not be indexed
|
||||||
HashLookupSettingsPanel.notApplicable=N/A
|
HashLookupSettingsPanel.notApplicable=N/A
|
||||||
HashLookupSettingsPanel.promptMessage.deleteHashDb=This will make the hash database unavailable for lookup. Do you want to proceed?\n\nNote: The hash database can still be re-imported later.
|
HashLookupSettingsPanel.promptMessage.deleteHashDb=This will make the hash database unavailable for lookup. Do you want to proceed?\n\nNote: The hash database can still be re-imported later.
|
||||||
HashLookupSettingsPanel.promptTitle.deleteHashDb=Delete Hash Database from Configuration
|
HashLookupSettingsPanel.promptTitle.deleteHashDb=Delete Hash Database from Configuration
|
||||||
HashLookupSettingsPanel.readOnly=Read only
|
HashLookupSettingsPanel.readOnly=Read only
|
||||||
# {0} - hash lookup name
|
# {0} - hash lookup name
|
||||||
HashLookupSettingsPanel.removeDatabaseFailure.message=Failed to remove hash lookup: {0}
|
HashLookupSettingsPanel.removeDatabaseFailure.message=Failed to remove hash lookup: {0}
|
||||||
|
# {0} - nsrlUrlAddress
|
||||||
|
HashLookupSettingsPanel.removeUnindexedNsrl.text=Instead of indexing the NSRL, please download an already indexed version available here:\n{0}
|
||||||
|
HashLookupSettingsPanel.removeUnindexedNsrl.title=Unindexed NSRL(s) will be removed
|
||||||
HashLookupSettingsPanel.saveFail.message=Couldn't save hash set settings.
|
HashLookupSettingsPanel.saveFail.message=Couldn't save hash set settings.
|
||||||
HashLookupSettingsPanel.saveFail.title=Save Fail
|
HashLookupSettingsPanel.saveFail.title=Save Fail
|
||||||
HashLookupSettingsPanel.Title=Global Hash Lookup Settings
|
HashLookupSettingsPanel.Title=Global Hash Lookup Settings
|
||||||
|
# {0} - nsrlHashSet
|
||||||
|
HashLookupSettingsPanel.unindexedNsrl.base=The following hash set appears to be an unindexed version of the NSRL, it will be removed from the list.\nHash set:{0}\n
|
||||||
|
# {0} - nsrlHashSets
|
||||||
|
HashLookupSettingsPanel.unindexedNsrls.base=The following hash sets appear to be unindexed versions of the NSRL, they will be removed from the list.\nHash sets:{0}\n
|
||||||
HashLookupSettingsPanel.updateStatusError=Error reading status
|
HashLookupSettingsPanel.updateStatusError=Error reading status
|
||||||
ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash set file
|
ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash set file
|
||||||
ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed
|
ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -25,7 +25,6 @@ import java.awt.Frame;
|
|||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -45,6 +44,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
|||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
|
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
||||||
@ -61,12 +61,15 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb;
|
|||||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
|
public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
|
||||||
|
|
||||||
|
private static final String NSRL_URL = "https://sourceforge.net/projects/autopsy/files/NSRL/";
|
||||||
|
private static final String NSRL_NAME_STRING = "nsrl";
|
||||||
private static final String NO_SELECTION_TEXT = NbBundle
|
private static final String NO_SELECTION_TEXT = NbBundle
|
||||||
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.noSelectionText");
|
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.noSelectionText");
|
||||||
private static final String ERROR_GETTING_PATH_TEXT = NbBundle
|
private static final String ERROR_GETTING_PATH_TEXT = NbBundle
|
||||||
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingPathText");
|
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingPathText");
|
||||||
private static final String ERROR_GETTING_INDEX_STATUS_TEXT = NbBundle
|
private static final String ERROR_GETTING_INDEX_STATUS_TEXT = NbBundle
|
||||||
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingIndexStatusText");
|
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingIndexStatusText");
|
||||||
|
private static final Logger logger = Logger.getLogger(HashLookupSettingsPanel.class.getName());
|
||||||
private final HashDbManager hashSetManager = HashDbManager.getInstance();
|
private final HashDbManager hashSetManager = HashDbManager.getInstance();
|
||||||
private final HashSetTableModel hashSetTableModel = new HashSetTableModel();
|
private final HashSetTableModel hashSetTableModel = new HashSetTableModel();
|
||||||
private final List<Integer> newReferenceSetIDs = new ArrayList<>();
|
private final List<Integer> newReferenceSetIDs = new ArrayList<>();
|
||||||
@ -320,10 +323,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
//If unindexed ones are found, show a popup box that will either index them, or remove them.
|
//If unindexed ones are found, show a popup box that will either index them, or remove them.
|
||||||
if (unindexed.size() == 1) {
|
if (!unindexed.isEmpty()) {
|
||||||
showInvalidIndex(false, unindexed);
|
showInvalidIndex(unindexed);
|
||||||
} else if (unindexed.size() > 1) {
|
|
||||||
showInvalidIndex(true, unindexed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -394,16 +395,45 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
|||||||
* @param plural Whether or not there are multiple unindexed databases
|
* @param plural Whether or not there are multiple unindexed databases
|
||||||
* @param unindexed The list of unindexed databases. Can be of size 1.
|
* @param unindexed The list of unindexed databases. Can be of size 1.
|
||||||
*/
|
*/
|
||||||
private void showInvalidIndex(boolean plural, List<SleuthkitHashSet> unindexed) {
|
@NbBundle.Messages({"# {0} - nsrlUrlAddress",
|
||||||
|
"HashLookupSettingsPanel.removeUnindexedNsrl.text=Instead of indexing the NSRL, please download an already indexed version available here:\n{0}",
|
||||||
|
"# {0} - nsrlHashSet",
|
||||||
|
"HashLookupSettingsPanel.unindexedNsrl.base=The following hash set appears to be an unindexed version of the NSRL, it will be removed from the list.\nHash set:{0}\n",
|
||||||
|
"# {0} - nsrlHashSets",
|
||||||
|
"HashLookupSettingsPanel.unindexedNsrls.base=The following hash sets appear to be unindexed versions of the NSRL, they will be removed from the list.\nHash sets:{0}\n",
|
||||||
|
"HashLookupSettingsPanel.removeUnindexedNsrl.title=Unindexed NSRL(s) will be removed"})
|
||||||
|
private void showInvalidIndex(List<SleuthkitHashSet> unindexed) {
|
||||||
String total = "";
|
String total = "";
|
||||||
String message;
|
String nsrlTotal = "";
|
||||||
for (HashDb hdb : unindexed) {
|
|
||||||
|
List<SleuthkitHashSet> nsrlHashsets = new ArrayList<>();
|
||||||
|
for (SleuthkitHashSet hdb : unindexed) {
|
||||||
|
//check if this is the NSRL if so point users toward already indexed versions
|
||||||
|
if (isWindows() && hdb.getHashSetName().toLowerCase().contains(NSRL_NAME_STRING)) {
|
||||||
|
nsrlHashsets.add(hdb);
|
||||||
|
nsrlTotal += "\n" + hdb.getHashSetName();
|
||||||
|
} else {
|
||||||
total += "\n" + hdb.getHashSetName();
|
total += "\n" + hdb.getHashSetName();
|
||||||
}
|
}
|
||||||
if (plural) {
|
}
|
||||||
message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbsNotIndexedMsg", total);
|
if (!nsrlHashsets.isEmpty()) {
|
||||||
|
String message;
|
||||||
|
if (nsrlHashsets.size() > 1) {
|
||||||
|
message = Bundle.HashLookupSettingsPanel_unindexedNsrls_base(nsrlTotal) + Bundle.HashLookupSettingsPanel_removeUnindexedNsrl_text(NSRL_URL);
|
||||||
} else {
|
} else {
|
||||||
message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbNotIndexedMsg", total);
|
message = Bundle.HashLookupSettingsPanel_unindexedNsrl_base(nsrlTotal) + Bundle.HashLookupSettingsPanel_removeUnindexedNsrl_text(NSRL_URL);
|
||||||
|
}
|
||||||
|
JOptionPane.showMessageDialog(this, message, Bundle.HashLookupSettingsPanel_removeUnindexedNsrl_title(), JOptionPane.INFORMATION_MESSAGE);
|
||||||
|
for (SleuthkitHashSet hdb : nsrlHashsets) {
|
||||||
|
unindexed.remove(hdb);
|
||||||
|
}
|
||||||
|
removeThese(nsrlHashsets);
|
||||||
|
}
|
||||||
|
String message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbNotIndexedMsg", total);
|
||||||
|
if (unindexed.isEmpty()) {
|
||||||
|
return;
|
||||||
|
} else if (unindexed.size() > 1) {
|
||||||
|
message = NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.dbsNotIndexedMsg", total);
|
||||||
}
|
}
|
||||||
int res = JOptionPane.showConfirmDialog(this, message,
|
int res = JOptionPane.showConfirmDialog(this, message,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
@ -948,6 +978,17 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
|||||||
}
|
}
|
||||||
}//GEN-LAST:event_sendIngestMessagesCheckBoxActionPerformed
|
}//GEN-LAST:event_sendIngestMessagesCheckBoxActionPerformed
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the current OS is windows
|
||||||
|
*
|
||||||
|
* @return true if running on windows, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean isWindows() {
|
||||||
|
return PlatformUtil.getOSName().toLowerCase().startsWith("Windows");
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({"HashLookupSettingsPanel.indexNsrl.text=This hash set appears to be the NSRL, it will be removed from the list.\n",
|
||||||
|
"HashLookupSettingsPanel.indexNsrl.title=NSRL will not be indexed"})
|
||||||
private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed
|
private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed
|
||||||
final HashDb hashDatabase = ((HashSetTable) hashSetTable).getSelection();
|
final HashDb hashDatabase = ((HashSetTable) hashSetTable).getSelection();
|
||||||
assert hashDatabase != null;
|
assert hashDatabase != null;
|
||||||
@ -956,6 +997,16 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
|||||||
// Add a listener for the INDEXING_DONE event. This listener will update
|
// Add a listener for the INDEXING_DONE event. This listener will update
|
||||||
// the UI.
|
// the UI.
|
||||||
SleuthkitHashSet hashDb = (SleuthkitHashSet) hashDatabase;
|
SleuthkitHashSet hashDb = (SleuthkitHashSet) hashDatabase;
|
||||||
|
if (isWindows() && hashDb.getHashSetName().toLowerCase().contains(NSRL_NAME_STRING)) {
|
||||||
|
JOptionPane.showMessageDialog(this, Bundle.HashLookupSettingsPanel_indexNsrl_text() + Bundle.HashLookupSettingsPanel_removeUnindexedNsrl_text(NSRL_URL), Bundle.HashLookupSettingsPanel_indexNsrl_title(), JOptionPane.INFORMATION_MESSAGE);
|
||||||
|
try {
|
||||||
|
hashSetManager.removeHashDatabaseNoSave(hashDatabase);
|
||||||
|
hashSetTableModel.refreshModel();
|
||||||
|
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||||
|
} catch (HashDbManager.HashDbManagerException ex) {
|
||||||
|
logger.log(Level.WARNING, "Unable to remove unindexed NSRL from hash set list", ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
hashDb.addPropertyChangeListener(new PropertyChangeListener() {
|
hashDb.addPropertyChangeListener(new PropertyChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
@ -978,6 +1029,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
|||||||
indexDialog.setLocationRelativeTo(null);
|
indexDialog.setLocationRelativeTo(null);
|
||||||
indexDialog.setVisible(true);
|
indexDialog.setVisible(true);
|
||||||
indexDialog.setModal(true);
|
indexDialog.setModal(true);
|
||||||
|
}
|
||||||
}//GEN-LAST:event_indexButtonActionPerformed
|
}//GEN-LAST:event_indexButtonActionPerformed
|
||||||
|
|
||||||
private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed
|
private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed
|
||||||
|
@ -45,6 +45,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
@ -59,7 +60,7 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
|||||||
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.ContentViewerTag;
|
import org.sleuthkit.autopsy.casemodule.services.contentviewertags.ContentViewerTagManager.ContentViewerTag;
|
||||||
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion;
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagRegion;
|
||||||
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtility;
|
import org.sleuthkit.autopsy.contentviewers.imagetagging.ImageTagsUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -805,10 +806,10 @@ class ReportHTML implements TableReportModule {
|
|||||||
|
|
||||||
if(!imageTags.isEmpty()) {
|
if(!imageTags.isEmpty()) {
|
||||||
//Write the tags to the fullsize and thumbnail images
|
//Write the tags to the fullsize and thumbnail images
|
||||||
BufferedImage fullImageWithTags = ImageTagsUtility.writeTags(file, imageTags, "png");
|
BufferedImage fullImageWithTags = ImageTagsUtil.getImageWithTags(file, imageTags);
|
||||||
|
|
||||||
BufferedImage thumbnailImageWithTags = ImageTagsUtility.makeThumbnail(file,
|
BufferedImage thumbnailWithTags = ImageTagsUtil.getThumbnailWithTags(file,
|
||||||
imageTags, ImageTagsUtility.IconSize.MEDIUM, "png");
|
imageTags, ImageTagsUtil.IconSize.MEDIUM);
|
||||||
|
|
||||||
String fileName = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(file.getName());
|
String fileName = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(file.getName());
|
||||||
|
|
||||||
@ -819,7 +820,7 @@ class ReportHTML implements TableReportModule {
|
|||||||
File fullImageWithTagsFile = Paths.get(fullImageWithTagsPath).toFile();
|
File fullImageWithTagsFile = Paths.get(fullImageWithTagsPath).toFile();
|
||||||
|
|
||||||
//Save images
|
//Save images
|
||||||
ImageIO.write(thumbnailImageWithTags, "png", thumbnailImageWithTagsFile);
|
ImageIO.write(thumbnailWithTags, "png", thumbnailImageWithTagsFile);
|
||||||
ImageIO.write(fullImageWithTags, "png", fullImageWithTagsFile);
|
ImageIO.write(fullImageWithTags, "png", fullImageWithTagsFile);
|
||||||
|
|
||||||
thumbnailPath = THUMBS_REL_PATH + thumbnailImageWithTagsFile.getName();
|
thumbnailPath = THUMBS_REL_PATH + thumbnailImageWithTagsFile.getName();
|
||||||
@ -828,7 +829,7 @@ class ReportHTML implements TableReportModule {
|
|||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.WARNING, "Could not get tags for file.", ex); //NON-NLS
|
logger.log(Level.WARNING, "Could not get tags for file.", ex); //NON-NLS
|
||||||
} catch (IOException ex) {
|
} catch (IOException | InterruptedException | ExecutionException ex) {
|
||||||
logger.log(Level.WARNING, "Could make marked up thumbnail.", ex); //NON-NLS
|
logger.log(Level.WARNING, "Could make marked up thumbnail.", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2019 Basis Technology Corp.
|
* Copyright 2014-2019 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -91,6 +91,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
public final class TimeLineTopComponent extends TopComponent implements ExplorerManager.Provider {
|
public final class TimeLineTopComponent extends TopComponent implements ExplorerManager.Provider {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
private static final Logger logger = Logger.getLogger(TimeLineTopComponent.class.getName());
|
private static final Logger logger = Logger.getLogger(TimeLineTopComponent.class.getName());
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
@ -102,7 +103,7 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||||
private final ExplorerManager explorerManager = new ExplorerManager();
|
private final ExplorerManager explorerManager = new ExplorerManager();
|
||||||
|
|
||||||
private final TimeLineController controller;
|
private TimeLineController controller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup that will be exposed through the (Global Actions Context)
|
* Lookup that will be exposed through the (Global Actions Context)
|
||||||
@ -253,11 +254,12 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructs a "shell" version of the top component for the Timeline
|
||||||
*
|
* feature which has only Swing components, no controller, and no listeners.
|
||||||
* @param controller The TimeLineController for this topcomponent.
|
* This constructor conforms to the NetBeans window system requirement that
|
||||||
|
* all top components have a public, no argument constructor.
|
||||||
*/
|
*/
|
||||||
public TimeLineTopComponent(TimeLineController controller) {
|
public TimeLineTopComponent() {
|
||||||
initComponents();
|
initComponents();
|
||||||
associateLookup(proxyLookup);
|
associateLookup(proxyLookup);
|
||||||
setName(NbBundle.getMessage(TimeLineTopComponent.class, "CTL_TimeLineTopComponent"));
|
setName(NbBundle.getMessage(TimeLineTopComponent.class, "CTL_TimeLineTopComponent"));
|
||||||
@ -266,7 +268,6 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
getActionMap().put("addBookmarkTag", new AddBookmarkTagAction()); //NON-NLS
|
getActionMap().put("addBookmarkTag", new AddBookmarkTagAction()); //NON-NLS
|
||||||
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ExternalViewerShortcutAction.EXTERNAL_VIEWER_SHORTCUT, "useExternalViewer"); //NON-NLS
|
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ExternalViewerShortcutAction.EXTERNAL_VIEWER_SHORTCUT, "useExternalViewer"); //NON-NLS
|
||||||
getActionMap().put("useExternalViewer", ExternalViewerShortcutAction.getInstance()); //NON-NLS
|
getActionMap().put("useExternalViewer", ExternalViewerShortcutAction.getInstance()); //NON-NLS
|
||||||
this.controller = controller;
|
|
||||||
|
|
||||||
//create linked result and content views
|
//create linked result and content views
|
||||||
contentViewerPanel = new DataContentExplorerPanel();
|
contentViewerPanel = new DataContentExplorerPanel();
|
||||||
@ -278,6 +279,17 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
|||||||
|
|
||||||
dataResultPanel.open(); //get the explorermanager
|
dataResultPanel.open(); //get the explorermanager
|
||||||
contentViewerPanel.initialize();
|
contentViewerPanel.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a fully functional top component for the Timeline feature.
|
||||||
|
*
|
||||||
|
* @param controller The TimeLineController for this top component.
|
||||||
|
*/
|
||||||
|
public TimeLineTopComponent(TimeLineController controller) {
|
||||||
|
this();
|
||||||
|
|
||||||
|
this.controller = controller;
|
||||||
|
|
||||||
Platform.runLater(this::initFXComponents);
|
Platform.runLater(this::initFXComponents);
|
||||||
|
|
||||||
|
@ -41,6 +41,9 @@ public final class OpenCvLoader {
|
|||||||
* Return whether or not the OpenCV library has been loaded.
|
* Return whether or not the OpenCV library has been loaded.
|
||||||
*
|
*
|
||||||
* @return - true if the opencv library is loaded or false if it is not
|
* @return - true if the opencv library is loaded or false if it is not
|
||||||
|
* @throws UnsatisfiedLinkError - A COPY of the exception that prevented OpenCV from loading.
|
||||||
|
* Note that the stack trace in the exception can be confusing because it refers to a
|
||||||
|
* past invocation.
|
||||||
*/
|
*/
|
||||||
public static boolean isOpenCvLoaded() throws UnsatisfiedLinkError {
|
public static boolean isOpenCvLoaded() throws UnsatisfiedLinkError {
|
||||||
if (!OPEN_CV_LOADED) {
|
if (!OPEN_CV_LOADED) {
|
||||||
|
@ -99,13 +99,14 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
resultSet = None
|
resultSet = None
|
||||||
try:
|
try:
|
||||||
resultSet = statement.executeQuery(
|
resultSet = statement.executeQuery(
|
||||||
"SELECT address, date, read, type, subject, body FROM sms;")
|
"SELECT address, date, read, type, subject, body, thread_id FROM sms;")
|
||||||
while resultSet.next():
|
while resultSet.next():
|
||||||
address = resultSet.getString("address") # may be phone number, or other addresses
|
address = resultSet.getString("address") # may be phone number, or other addresses
|
||||||
date = Long.valueOf(resultSet.getString("date")) / 1000
|
date = Long.valueOf(resultSet.getString("date")) / 1000
|
||||||
read = resultSet.getInt("read") # may be unread = 0, read = 1
|
read = resultSet.getInt("read") # may be unread = 0, read = 1
|
||||||
subject = resultSet.getString("subject") # message subject
|
subject = resultSet.getString("subject") # message subject
|
||||||
body = resultSet.getString("body") # message body
|
body = resultSet.getString("body") # message body
|
||||||
|
thread_id = "{0}_{1}".format(abstractFile.getId(), resultSet.getInt("thread_id"))
|
||||||
attributes = ArrayList()
|
attributes = ArrayList()
|
||||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); #create Message artifact and then add attributes from result set.
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); #create Message artifact and then add attributes from result set.
|
||||||
if resultSet.getString("type") == "1":
|
if resultSet.getString("type") == "1":
|
||||||
@ -119,6 +120,7 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, general.MODULE_NAME, subject))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, general.MODULE_NAME, subject))
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, body))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, body))
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message"))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message"))
|
||||||
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID, general.MODULE_NAME, thread_id))
|
||||||
|
|
||||||
artifact.addAttributes(attributes)
|
artifact.addAttributes(attributes)
|
||||||
|
|
||||||
|
@ -41,6 +41,8 @@ from org.sleuthkit.datamodel import Content
|
|||||||
from org.sleuthkit.datamodel import TskCoreException
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
from org.sleuthkit.datamodel import Account
|
from org.sleuthkit.datamodel import Account
|
||||||
from org.sleuthkit.datamodel import Relationship
|
from org.sleuthkit.datamodel import Relationship
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestServices
|
||||||
|
from org.sleuthkit.autopsy.ingest import ModuleDataEvent
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
import general
|
import general
|
||||||
@ -79,6 +81,7 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
if not databasePath:
|
if not databasePath:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
bbartifacts = list()
|
||||||
try:
|
try:
|
||||||
Class.forName("org.sqlite.JDBC"); # load JDBC driver
|
Class.forName("org.sqlite.JDBC"); # load JDBC driver
|
||||||
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||||
@ -115,6 +118,7 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID, general.MODULE_NAME, game_id))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID, general.MODULE_NAME, game_id))
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, message))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, message))
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message"))
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message"))
|
||||||
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID, general.MODULE_NAME, user_id))
|
||||||
|
|
||||||
artifact.addAttributes(attributes)
|
artifact.addAttributes(attributes)
|
||||||
|
|
||||||
@ -124,6 +128,7 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
# create relationship between accounts
|
# create relationship between accounts
|
||||||
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [wwfAccountInstance], artifact,Relationship.Type.MESSAGE, created_at);
|
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [wwfAccountInstance], artifact,Relationship.Type.MESSAGE, created_at);
|
||||||
|
|
||||||
|
bbartifacts.append(artifact)
|
||||||
try:
|
try:
|
||||||
# index the artifact for keyword search
|
# index the artifact for keyword search
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
@ -140,6 +145,10 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
|
|||||||
self._logger.log(Level.SEVERE, "Error parsing WWF messages to the blackboard", ex)
|
self._logger.log(Level.SEVERE, "Error parsing WWF messages to the blackboard", ex)
|
||||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
finally:
|
finally:
|
||||||
|
if bbartifacts:
|
||||||
|
|
||||||
|
IngestServices.getInstance().fireModuleDataEvent(ModuleDataEvent(general.MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE, bbartifacts))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if resultSet is not None:
|
if resultSet is not None:
|
||||||
resultSet.close()
|
resultSet.close()
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<project name="TSK_VERSION">
|
<project name="TSK_VERSION">
|
||||||
<property name="TSK_VERSION" value="4.6.6"/>
|
<property name="TSK_VERSION" value="4.6.7"/>
|
||||||
</project>
|
</project>
|
||||||
|
@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation"
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 4.11.0
|
PROJECT_NUMBER = 4.12.0
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
@ -1025,7 +1025,7 @@ GENERATE_HTML = YES
|
|||||||
# The default directory is: html.
|
# The default directory is: html.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_OUTPUT = 4.11.0
|
HTML_OUTPUT = 4.12.0
|
||||||
|
|
||||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
||||||
# generated HTML page (for example: .htm, .php, .asp).
|
# generated HTML page (for example: .htm, .php, .asp).
|
||||||
|
@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy"
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 4.11.0
|
PROJECT_NUMBER = 4.12.0
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears a the top of each page and should give viewer a
|
# for a project that appears a the top of each page and should give viewer a
|
||||||
@ -1063,7 +1063,7 @@ GENERATE_HTML = YES
|
|||||||
# The default directory is: html.
|
# The default directory is: html.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_OUTPUT = api-docs/4.11.0/
|
HTML_OUTPUT = api-docs/4.12.0/
|
||||||
|
|
||||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
||||||
# generated HTML page (for example: .htm, .php, .asp).
|
# generated HTML page (for example: .htm, .php, .asp).
|
||||||
|
@ -4,10 +4,10 @@ app.title=Autopsy
|
|||||||
### lowercase version of above
|
### lowercase version of above
|
||||||
app.name=${branding.token}
|
app.name=${branding.token}
|
||||||
### if left unset, version will default to today's date
|
### if left unset, version will default to today's date
|
||||||
app.version=4.11.0
|
app.version=4.12.0
|
||||||
### build.type must be one of: DEVELOPMENT, RELEASE
|
### build.type must be one of: DEVELOPMENT, RELEASE
|
||||||
#build.type=RELEASE
|
build.type=RELEASE
|
||||||
build.type=DEVELOPMENT
|
#build.type=DEVELOPMENT
|
||||||
|
|
||||||
project.org.netbeans.progress=org-netbeans-api-progress
|
project.org.netbeans.progress=org-netbeans-api-progress
|
||||||
project.org.sleuthkit.autopsy.experimental=Experimental
|
project.org.sleuthkit.autopsy.experimental=Experimental
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
# NOTE: update_sleuthkit_version.pl updates this value and relies
|
# NOTE: update_sleuthkit_version.pl updates this value and relies
|
||||||
# on it keeping the same name and whitespace. Don't change it.
|
# on it keeping the same name and whitespace. Don't change it.
|
||||||
TSK_VERSION=4.6.6
|
TSK_VERSION=4.6.7
|
||||||
|
|
||||||
|
|
||||||
# In the beginning...
|
# In the beginning...
|
||||||
|
Loading…
x
Reference in New Issue
Block a user