Merge pull request #4914 from kellykelly3/1268-dynamic-account-types

1268 dynamic account types
This commit is contained in:
Richard Cordovano 2019-06-20 09:55:56 -04:00 committed by GitHub
commit a70a910fab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 143 additions and 50 deletions

View File

@ -66,7 +66,7 @@
</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="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>
</Constraints>
</Component>
@ -95,7 +95,7 @@
</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="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>
</Constraints>
@ -464,7 +464,7 @@
<Container class="javax.swing.JPanel" name="accountTypeListPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
<Property name="axis" type="int" value="1"/>
<Property name="axis" type="int" value="3"/>
</Layout>
</Container>
</SubComponents>

View File

@ -53,6 +53,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
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 org.sleuthkit.autopsy.ingest.ModuleDataEvent;
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.DeviceFilter;
import org.sleuthkit.datamodel.CommunicationsFilter.MostRecentFilter;
import org.sleuthkit.datamodel.CommunicationsManager;
import org.sleuthkit.datamodel.DataSource;
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
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
*/
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).
*/
private boolean needsRefresh;
@ -123,6 +126,11 @@ final public class FiltersPanel extends JPanel {
@NbBundle.Messages({"refreshText=Refresh Results", "applyText=Apply"})
public FiltersPanel() {
initComponents();
CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(Account.Type.DEVICE, true);
accountTypeMap.put(Account.Type.DEVICE, panel.getCheckBox());
accountTypeListPane.add(panel);
deviceRequiredLabel.setVisible(false);
accountTypeRequiredLabel.setVisible(false);
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
ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue();
if (null != eventData
&& eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
&& eventData.getBlackboardArtifactType().getTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
updateFilters(false);
&& (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()))
{
updateFilters(true);
needsRefresh = true;
validateFilters();
}
}
};
this.ingestJobListener = pce -> {
String eventType = pce.getPropertyName();
if (eventType.equals(COMPLETED.toString()) &&
updateFilters(true)) {
needsRefresh = true;
validateFilters();
}
}
};
applyFiltersButton.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.
*/
private void updateFilters(boolean initialState) {
updateAccountTypeFilter();
updateDeviceFilter(initialState);
private boolean updateFilters(boolean initialState) {
boolean newAccountType = updateAccountTypeFilter(initialState);
boolean newDeviceFilter = updateDeviceFilter(initialState);
// both or either are true, return true;
return newAccountType || newDeviceFilter;
}
@Override
public void addNotify() {
super.addNotify();
IngestManager.getInstance().addIngestModuleEventListener(ingestListener);
IngestManager.getInstance().addIngestJobEventListener(ingestJobListener);
Case.addEventTypeSubscriber(EnumSet.of(CURRENT_CASE), evt -> {
//clear the device filter widget when the case changes.
devicesMap.clear();
devicesListPane.removeAll();
accountTypeMap.clear();
accountTypeListPane.removeAll();
});
}
@ -239,64 +266,107 @@ final public class FiltersPanel extends JPanel {
public void removeNotify() {
super.removeNotify();
IngestManager.getInstance().removeIngestModuleEventListener(ingestListener);
IngestManager.getInstance().removeIngestJobEventListener(ingestJobListener);
}
/**
* 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() {
//TODO: something like this commented code could be used to show only
//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 -> {
CheckBoxIconPanel panel = new CheckBoxIconPanel(
type.getDisplayName(),
new ImageIcon(FiltersPanel.class.getResource(Utils.getIconFilePath(type))));
panel.setSelected(true);
panel.addItemListener(validationListener);
private boolean updateAccountTypeFilter(boolean selected) {
boolean newOneFound = false;
try {
final CommunicationsManager communicationsManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
List<Account.Type> accountTypesInUse = communicationsManager.getAccountTypesInUse();
for (Account.Type type : accountTypesInUse) {
if (!accountTypeMap.containsKey(type) && !type.equals(Account.Type.CREDIT_CARD)) {
CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(type, selected);
accountTypeMap.put(type, panel.getCheckBox());
accountTypeListPane.add(panel);
if (t.equals(Account.Type.DEVICE)) {
//Deveice type filter is enabled based on whether we are in table or graph view.
panel.setEnabled(deviceAccountTypeEnabled);
}
return panel.getCheckBox();
});
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(
type.getDisplayName(),
new ImageIcon(FiltersPanel.class.getResource(Utils.getIconFilePath(type))));
panel.setSelected(initalState);
panel.addItemListener(validationListener);
if (type.equals(Account.Type.DEVICE)) {
//Deveice type filter is enabled based on whether we are in table or graph view.
panel.setEnabled(deviceAccountTypeEnabled);
}
return panel;
}
/**
* 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 {
final SleuthkitCase sleuthkitCase = Case.getCurrentCaseThrows().getSleuthkitCase();
for (DataSource dataSource : sleuthkitCase.getDataSources()) {
String dsName = sleuthkitCase.getContentById(dataSource.getId()).getName();
//store the device id in the map, but display a datasource name in the UI.
devicesMap.computeIfAbsent(dataSource.getDeviceId(), ds -> {
final JCheckBox jCheckBox = new JCheckBox(dsName, initialState);
jCheckBox.addItemListener(validationListener);
devicesListPane.add(jCheckBox);
return jCheckBox;
});
if(devicesMap.containsKey(dataSource.getDeviceId())) {
continue;
}
final JCheckBox jCheckBox = new JCheckBox(dsName, selected);
jCheckBox.addItemListener(validationListener);
devicesListPane.add(jCheckBox);
devicesMap.put(dataSource.getDeviceId(), jCheckBox);
newOneFound = true;
}
} catch (NoCurrentCaseException ex) {
logger.log(Level.INFO, "Filter update cancelled. Case is closed.");
} catch (TskCoreException 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
*/
@ -366,6 +436,12 @@ final public class FiltersPanel extends JPanel {
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) {
int limit = filter.getLimit();
if(limit > 0) {
@ -424,6 +500,7 @@ final public class FiltersPanel extends JPanel {
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 5);
topPane.add(applyFiltersButton, gridBagConstraints);
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));
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);
gridBagConstraints = new java.awt.GridBagConstraints();
@ -740,6 +817,7 @@ final public class FiltersPanel extends JPanel {
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(9, 0, 0, 0);
add(scrollPane, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
@ -808,6 +886,11 @@ final public class FiltersPanel extends JPanel {
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() {
String value = (String)limitComboBox.getSelectedItem();
if(value.trim().equalsIgnoreCase("all")){

View File

@ -1845,7 +1845,8 @@ final public class Accounts implements AutopsyVisitableItem {
return ICON_BASE_PATH + "WhatsApp.png";
} else {
//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());
}
}
}

View File

@ -41,6 +41,8 @@ from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel import Account
from org.sleuthkit.datamodel import Relationship
from org.sleuthkit.autopsy.ingest import IngestServices
from org.sleuthkit.autopsy.ingest import ModuleDataEvent
import traceback
import general
@ -78,7 +80,8 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
def __findWWFMessagesInDB(self, databasePath, abstractFile, dataSource):
if not databasePath:
return
bbartifacts = list()
try:
Class.forName("org.sqlite.JDBC"); # load JDBC driver
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_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_THREAD_ID, general.MODULE_NAME, user_id))
artifact.addAttributes(attributes)
@ -124,6 +128,7 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
# create relationship between accounts
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [wwfAccountInstance], artifact,Relationship.Type.MESSAGE, created_at);
bbartifacts.append(artifact)
try:
# index the artifact for keyword search
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, traceback.format_exc())
finally:
if bbartifacts:
IngestServices.getInstance().fireModuleDataEvent(ModuleDataEvent(general.MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE, bbartifacts))
try:
if resultSet is not None:
resultSet.close()