mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +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-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.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-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
|
||||
|
@ -482,8 +482,8 @@
|
||||
<binary-origin>release\modules\ext\jmatio-1.5.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.6.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.6.jar</binary-origin>
|
||||
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.7.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.7.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<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());
|
||||
addItemToBag(gridY, 0, 0, 0, knownStatusLabel);
|
||||
javax.swing.JLabel knownStatusValue = new javax.swing.JLabel();
|
||||
knownStatusValue.setText(knownStatus.toString());
|
||||
knownStatusValue.setText(knownStatus.getName());
|
||||
if (knownStatus == TskData.FileKnown.BAD) {
|
||||
knownStatusValue.setForeground(Color.RED);
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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() {
|
||||
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
|
||||
//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 -> {
|
||||
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);
|
||||
|
||||
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(true);
|
||||
|
||||
panel.setSelected(initalState);
|
||||
panel.addItemListener(validationListener);
|
||||
accountTypeListPane.add(panel);
|
||||
if (t.equals(Account.Type.DEVICE)) {
|
||||
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.getCheckBox();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
if(devicesMap.containsKey(dataSource.getDeviceId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final JCheckBox jCheckBox = new JCheckBox(dsName, selected);
|
||||
jCheckBox.addItemListener(validationListener);
|
||||
devicesListPane.add(jCheckBox);
|
||||
return 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")){
|
||||
|
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.messagesLabel.text=Messages:
|
||||
SummaryViewer.callLogsLabel.text=Call Logs:
|
||||
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
|
||||
|
@ -19,12 +19,16 @@ MessageNode_Node_Property_Subject=Subject
|
||||
MessageNode_Node_Property_To=To
|
||||
MessageNode_Node_Property_Type=Type
|
||||
MessageViewer_columnHeader_Attms=Attachments
|
||||
MessageViewer_columnHeader_Date=Date
|
||||
MessageViewer_columnHeader_Date=Data
|
||||
MessageViewer_columnHeader_EarlyDate=Earliest Message
|
||||
MessageViewer_columnHeader_From=From
|
||||
MessageViewer_columnHeader_Subject=Subject
|
||||
MessageViewer_columnHeader_To=To
|
||||
MessageViewer_no_messages=<No messages found for selected account>
|
||||
MessageViewer_tabTitle=Messages
|
||||
MessageViewer_viewMessage_all=All
|
||||
MessageViewer_viewMessage_selected=Selected
|
||||
MessageViewer_viewMessage_unthreaded=Unthreaded
|
||||
SummaryViewer.countsPanel.border.title=Counts
|
||||
SummaryViewer.emailLabel.text=Emails:
|
||||
SummaryViewer.contactsLabel.text=Contacts:
|
||||
@ -37,11 +41,19 @@ SummaryViewer.emailDataLabel.text=emails
|
||||
SummaryViewer.attachmentsDataLabel.text=attachments
|
||||
SummaryViewer.messagesLabel.text=Messages:
|
||||
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_CentralRepository_Message=<Enable Central Resposity to see Other Occurrences>
|
||||
SummaryViewer_Creation_Date_Title=Creation Date
|
||||
SummaryViewer_FileRefNameColumn_Title=Path
|
||||
SummaryViewer_TabTitle=Summary
|
||||
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"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="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>
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="nameLabel">
|
||||
<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}")"/>
|
||||
</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="16" insetsLeft="15" insetsBottom="15" insetsRight="15" anchor="23" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="org.openide.explorer.propertysheet.PropertySheet" name="propertySheet">
|
||||
<Properties>
|
||||
<Property name="descriptionAreaVisible" type="boolean" value="false"/>
|
||||
</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>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -73,38 +73,36 @@ public final class ContactDetailsPane extends javax.swing.JPanel implements Expl
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
messageContentViewer1 = new org.sleuthkit.autopsy.contentviewers.MessageContentViewer();
|
||||
nameLabel = new javax.swing.JLabel();
|
||||
propertySheet = new org.openide.explorer.propertysheet.PropertySheet();
|
||||
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.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())
|
||||
);
|
||||
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(9, 15, 16, 15);
|
||||
add(propertySheet, gridBagConstraints);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
|
@ -36,7 +36,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* ChildFactory for ContactNodes.
|
||||
*/
|
||||
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;
|
||||
|
||||
|
@ -130,9 +130,7 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
|
||||
logger.log(Level.WARNING, "Unable to update selection." , ex);
|
||||
}
|
||||
|
||||
if(artifactList.size() == 0) {
|
||||
thumbnailViewer.resetComponent();
|
||||
}
|
||||
|
||||
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.logging.Level;
|
||||
import javax.swing.Action;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
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.TskCoreException;
|
||||
import org.sleuthkit.autopsy.communications.Utils;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
|
||||
/**
|
||||
* 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());
|
||||
|
||||
MessageNode(BlackboardArtifact artifact) {
|
||||
private final String threadID;
|
||||
|
||||
private final Action preferredAction;
|
||||
|
||||
MessageNode(BlackboardArtifact artifact, String threadID, Action preferredAction) {
|
||||
super(artifact);
|
||||
|
||||
this.preferredAction = preferredAction;
|
||||
|
||||
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS
|
||||
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS
|
||||
setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase);
|
||||
|
||||
this.threadID = threadID;
|
||||
}
|
||||
|
||||
@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<>("ThreadID", "ThreadID","",threadID == null ? UNTHREADED_ID : threadID)); //NON-NLS
|
||||
|
||||
final BlackboardArtifact artifact = getArtifact();
|
||||
|
||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
||||
@ -167,4 +180,13 @@ final class MessageNode extends BlackboardArtifactNode {
|
||||
public String getSourceName() {
|
||||
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.coreutils.Logger;
|
||||
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.
|
||||
* A ChildFactory subclass for creating MessageNodes from a set of
|
||||
* 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 SelectionInfo selectionInfo;
|
||||
|
||||
/**
|
||||
* Construct a new MessageChildNodeFactory from the currently selectionInfo
|
||||
*
|
||||
* @param selectionInfo SelectionInfo object for the currently selected
|
||||
* accounts
|
||||
*/
|
||||
MessagesChildNodeFactory(SelectionInfo selectionInfo) {
|
||||
private List<String> threadIDs;
|
||||
|
||||
MessagesChildNodeFactory(SelectionInfo selectionInfo, List<String> threadIDs) {
|
||||
this.selectionInfo = selectionInfo;
|
||||
this.threadIDs = threadIDs;
|
||||
}
|
||||
|
||||
MessagesChildNodeFactory() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current instance of selectionInfo and calls the refresh method.
|
||||
*
|
||||
* @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;
|
||||
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) {
|
||||
@ -87,19 +86,37 @@ final class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact> {
|
||||
final Set<Content> relationshipSources;
|
||||
|
||||
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.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) {
|
||||
if (fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
|
||||
&& fromID != BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
|
||||
&& 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);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
|
||||
@ -110,6 +127,7 @@ final class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact> {
|
||||
|
||||
@Override
|
||||
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" ?>
|
||||
|
||||
<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>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||
<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_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,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>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JSplitPane" name="splitPane">
|
||||
<Properties>
|
||||
<Property name="orientation" type="int" value="0"/>
|
||||
</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="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="Center"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||
<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">
|
||||
<Constraints>
|
||||
<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>
|
||||
</Constraints>
|
||||
</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>
|
||||
</Container>
|
||||
</SubComponents>
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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
|
||||
*
|
||||
@ -22,57 +22,38 @@ import java.awt.Component;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.JPanel;
|
||||
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.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.NodeAdapter;
|
||||
import org.openide.nodes.NodeMemberEvent;
|
||||
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.corecomponents.TableFilterNode;
|
||||
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 final class MessagesViewer extends JPanel implements RelationshipsViewer {
|
||||
public class MessagesPanel extends javax.swing.JPanel implements Lookup.Provider {
|
||||
|
||||
private final Outline outline;
|
||||
private final ModifiableProxyLookup proxyLookup;
|
||||
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();
|
||||
|
||||
splitPane.setResizeWeight(0.5);
|
||||
|
||||
outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages());
|
||||
|
||||
proxyLookup = new ModifiableProxyLookup(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
|
||||
nodeFactory = new MessagesChildNodeFactory(null);
|
||||
|
||||
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
|
||||
// explaination of focusPropertyListener
|
||||
@ -83,10 +64,10 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
||||
if (newFocusOwner == null) {
|
||||
return;
|
||||
}
|
||||
if (isDescendingFrom(newFocusOwner, contentViewer)) {
|
||||
if (isDescendingFrom(newFocusOwner, messageContentViewer)) {
|
||||
//if the focus owner is within the MessageContentViewer (the attachments table)
|
||||
proxyLookup.setNewLookups(createLookup(((MessageDataContent) contentViewer).getExplorerManager(), getActionMap()));
|
||||
} else if (isDescendingFrom(newFocusOwner, MessagesViewer.this)) {
|
||||
proxyLookup.setNewLookups(createLookup(((MessageDataContent) messageContentViewer).getExplorerManager(), getActionMap()));
|
||||
} else if (isDescendingFrom(newFocusOwner, MessagesPanel.this)) {
|
||||
//... or if it is within the Results table.
|
||||
proxyLookup.setNewLookups(createLookup(outlineViewPanel.getExplorerManager(), getActionMap()));
|
||||
|
||||
@ -110,52 +91,22 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
||||
final Node[] nodes = outlineViewPanel.getExplorerManager().getSelectedNodes();
|
||||
|
||||
if (nodes != null && nodes.length == 1) {
|
||||
contentViewer.setNode(nodes[0]);
|
||||
messageContentViewer.setNode(nodes[0]);
|
||||
}
|
||||
else {
|
||||
contentViewer.setNode(null);
|
||||
messageContentViewer.setNode(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
outlineViewPanel.getExplorerManager().setRootContext(
|
||||
new TableFilterNode(
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
splitPane.setResizeWeight(0.5);
|
||||
splitPane.setDividerLocation(0.5);
|
||||
outlineViewPanel.setTableColumnsWidth(5,10,10,15,50,10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return Bundle.MessageViewer_tabTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectionInfo(SelectionInfo info) {
|
||||
nodeFactory.refresh(info);
|
||||
public MessagesPanel(ChildFactory<?> nodeFactory) {
|
||||
this();
|
||||
setChildFactory(nodeFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -178,13 +129,13 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
||||
.removePropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
private void updateOutlineViewPanel() {
|
||||
int nodeCount = outlineViewPanel.getExplorerManager().getRootContext().getChildren().getNodesCount();
|
||||
if(nodeCount == 0) {
|
||||
outlineViewPanel.hideOutlineView(Bundle.MessageViewer_no_messages());
|
||||
} else {
|
||||
outlineViewPanel.showOutlineView();
|
||||
}
|
||||
final void setChildFactory(ChildFactory<?> nodeFactory) {
|
||||
outlineViewPanel.getExplorerManager().setRootContext(
|
||||
new TableFilterNode(
|
||||
new DataResultFilterNode(
|
||||
new AbstractNode(
|
||||
Children.create(nodeFactory, true)),
|
||||
outlineViewPanel.getExplorerManager()),true));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,31 +146,23 @@ public final class MessagesViewer extends JPanel implements RelationshipsViewer
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
splitPane = new javax.swing.JSplitPane();
|
||||
contentViewer = new MessageDataContent();
|
||||
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.setBottomComponent(contentViewer);
|
||||
splitPane.setLeftComponent(outlineViewPanel);
|
||||
splitPane.setRightComponent(messageContentViewer);
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
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);
|
||||
add(splitPane, java.awt.BorderLayout.CENTER);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// 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 javax.swing.JSplitPane splitPane;
|
||||
// End of variables declaration//GEN-END:variables
|
@ -1,9 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<Properties>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
@ -23,12 +20,6 @@
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<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>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
|
||||
<CardConstraints cardName="outlineCard"/>
|
||||
|
@ -101,6 +101,15 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana
|
||||
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) {
|
||||
JTable table = outlineView.getOutline();
|
||||
double total = 0;
|
||||
@ -127,11 +136,7 @@ public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerMana
|
||||
messagePanel = new javax.swing.JPanel();
|
||||
messageLabel = new javax.swing.JLabel();
|
||||
|
||||
setEnabled(false);
|
||||
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");
|
||||
|
||||
messagePanel.setLayout(new java.awt.BorderLayout());
|
||||
|
@ -11,7 +11,6 @@
|
||||
<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,1,44,0,0,1,-112"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
@ -22,7 +21,7 @@
|
||||
</Events>
|
||||
<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="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>
|
||||
</Constraints>
|
||||
|
||||
|
@ -31,7 +31,7 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
|
||||
|
||||
private SelectionInfo currentSelection;
|
||||
|
||||
private final MessagesViewer messagesViewer;
|
||||
private final MessageViewer messagesViewer;
|
||||
private final ContactsViewer contactsViewer;
|
||||
private final SummaryViewer summaryViewer;
|
||||
private final MediaViewer mediaViewer;
|
||||
@ -42,15 +42,14 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
|
||||
* Creates new form RelationshipBrowser
|
||||
*/
|
||||
public RelationshipBrowser() {
|
||||
messagesViewer = new MessagesViewer();
|
||||
initComponents();
|
||||
messagesViewer = new MessageViewer();
|
||||
contactsViewer = new ContactsViewer();
|
||||
summaryViewer = new SummaryViewer();
|
||||
mediaViewer = new MediaViewer();
|
||||
|
||||
proxyLookup = new ModifiableProxyLookup(messagesViewer.getLookup());
|
||||
|
||||
initComponents();
|
||||
|
||||
tabPane.add(summaryViewer.getDisplayName(), summaryViewer);
|
||||
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
|
||||
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
|
||||
* currently selected or visible tab.
|
||||
* currently selected\visible tab.
|
||||
*
|
||||
* @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.weightx = 1.0;
|
||||
gridBagConstraints.weighty = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(1, 1, 1, 1);
|
||||
add(tabPane, gridBagConstraints);
|
||||
}// </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.PropertyChangeSupport;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
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.ContentViewerTag;
|
||||
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.ImageTagRegion;
|
||||
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());
|
||||
|
||||
//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(),
|
||||
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());
|
||||
} 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
|
||||
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));
|
||||
try {
|
||||
if (rootNode != null) {
|
||||
this.rootNode = rootNode;
|
||||
|
||||
/**
|
||||
* Check to see if we have previously created a paging support
|
||||
* class for this node.
|
||||
@ -364,8 +366,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
* case database round trips.
|
||||
*/
|
||||
if (rootNode != null && rootNode.getChildren().getNodesCount() > 0) {
|
||||
this.rootNode = rootNode;
|
||||
|
||||
this.getExplorerManager().setRootContext(this.rootNode);
|
||||
setupTable();
|
||||
} else {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -490,6 +490,12 @@ public class DataResultFilterNode extends FilterNode {
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(BlackboardArtifactNode ban) {
|
||||
|
||||
Action preferredAction = ban.getPreferredAction();
|
||||
if(preferredAction instanceof AbstractAction) {
|
||||
return (AbstractAction) preferredAction;
|
||||
}
|
||||
|
||||
BlackboardArtifact artifact = ban.getArtifact();
|
||||
try {
|
||||
if ((artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2014-2018 Basis Technology Corp.
|
||||
* Copyright 2014-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* 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(secondStageDataSourceModuleTemplates, IngestModuleType.DATA_SOURCE_LEVEL, skCase);
|
||||
} 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 {
|
||||
this.ingestJob = Case.getCurrentCaseThrows().getSleuthkitCase().addIngestJob(dataSource, NetworkUtils.getLocalHostName(), ingestModules, new Date(this.createTime), new Date(0), IngestJobStatusType.STARTED, "");
|
||||
} 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()) {
|
||||
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();
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
@ -521,13 +521,13 @@ public final class DataSourceIngestJob {
|
||||
* Schedule the first stage tasks.
|
||||
*/
|
||||
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);
|
||||
} 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);
|
||||
} 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);
|
||||
|
||||
/**
|
||||
@ -546,7 +546,7 @@ public final class DataSourceIngestJob {
|
||||
* Starts the second stage of this ingest job.
|
||||
*/
|
||||
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;
|
||||
if (this.doUI) {
|
||||
this.startDataSourceIngestProgressBar();
|
||||
@ -554,7 +554,7 @@ public final class DataSourceIngestJob {
|
||||
synchronized (this.dataSourceIngestPipelineLock) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -643,7 +643,7 @@ public final class DataSourceIngestJob {
|
||||
* job and starts the second stage, if appropriate.
|
||||
*/
|
||||
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
|
||||
// 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.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (this.doUI) {
|
||||
@ -711,19 +711,19 @@ public final class DataSourceIngestJob {
|
||||
try {
|
||||
ingestJob.setIngestJobStatus(IngestJobStatusType.CANCELLED);
|
||||
} 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 {
|
||||
try {
|
||||
ingestJob.setIngestJobStatus(IngestJobStatusType.COMPLETED);
|
||||
} 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 {
|
||||
this.ingestJob.setEndDateTime(new Date());
|
||||
} 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);
|
||||
@ -842,7 +842,7 @@ public final class DataSourceIngestJob {
|
||||
if (DataSourceIngestJob.Stages.FIRST == this.stage) {
|
||||
DataSourceIngestJob.taskScheduler.fastTrackFileIngestTasks(this, files);
|
||||
} 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -1073,7 +1106,7 @@ public final class DataSourceIngestJob {
|
||||
*/
|
||||
private void logIngestModuleErrors(List<IngestModuleError> 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
|
||||
*
|
||||
* Copyright 2012-2018 Basis Technology Corp.
|
||||
* Copyright 2012-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -403,10 +403,10 @@ public class IngestManager implements IngestProgressSnapshotProvider {
|
||||
synchronized (ingestJobsById) {
|
||||
ingestJobsById.put(job.getId(), job);
|
||||
}
|
||||
IngestManager.logger.log(Level.INFO, "Starting ingest job {0}", job.getId()); //NON-NLS
|
||||
errors = job.start();
|
||||
if (errors.isEmpty()) {
|
||||
this.fireIngestJobStarted(job.getId());
|
||||
IngestManager.logger.log(Level.INFO, "Ingest job {0} started", job.getId()); //NON-NLS
|
||||
} else {
|
||||
synchronized (ingestJobsById) {
|
||||
this.ingestJobsById.remove(job.getId());
|
||||
|
@ -135,7 +135,7 @@ final class ConfigVisualPanel1 extends JPanel {
|
||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
FileFilter filter = new FileNameExtensionFilter(Bundle.ConfigVisualPanel1_fileNameExtensionFilter(), new String[] {"json"}); // NON-NLS
|
||||
fileChooser.setFileFilter(filter);
|
||||
fileChooser.setSelectedFile(new File("config.json")); // default
|
||||
fileChooser.setSelectedFile(new File("logical-imager-config.json")); // default
|
||||
fileChooser.setMultiSelectionEnabled(false);
|
||||
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
||||
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.
|
||||
HashLookupSettingsPanel.centralRepo=Central Repository
|
||||
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.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.readOnly=Read only
|
||||
# {0} - hash lookup name
|
||||
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.title=Save Fail
|
||||
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
|
||||
ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash set file
|
||||
ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* 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.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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.corecomponents.OptionsPanel;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
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
|
||||
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
|
||||
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.noSelectionText");
|
||||
private static final String ERROR_GETTING_PATH_TEXT = NbBundle
|
||||
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingPathText");
|
||||
private static final String ERROR_GETTING_INDEX_STATUS_TEXT = NbBundle
|
||||
.getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingIndexStatusText");
|
||||
private static final Logger logger = Logger.getLogger(HashLookupSettingsPanel.class.getName());
|
||||
private final HashDbManager hashSetManager = HashDbManager.getInstance();
|
||||
private final HashSetTableModel hashSetTableModel = new HashSetTableModel();
|
||||
private final List<Integer> newReferenceSetIDs = new ArrayList<>();
|
||||
@ -320,10 +323,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
||||
@Override
|
||||
public void run() {
|
||||
//If unindexed ones are found, show a popup box that will either index them, or remove them.
|
||||
if (unindexed.size() == 1) {
|
||||
showInvalidIndex(false, unindexed);
|
||||
} else if (unindexed.size() > 1) {
|
||||
showInvalidIndex(true, unindexed);
|
||||
if (!unindexed.isEmpty()) {
|
||||
showInvalidIndex(unindexed);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -394,16 +395,45 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
||||
* @param plural Whether or not there are multiple unindexed databases
|
||||
* @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 message;
|
||||
for (HashDb hdb : unindexed) {
|
||||
String nsrlTotal = "";
|
||||
|
||||
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();
|
||||
}
|
||||
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 {
|
||||
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,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
@ -948,6 +978,17 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
||||
}
|
||||
}//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
|
||||
final HashDb hashDatabase = ((HashSetTable) hashSetTable).getSelection();
|
||||
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
|
||||
// the UI.
|
||||
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() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
@ -978,6 +1029,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
||||
indexDialog.setLocationRelativeTo(null);
|
||||
indexDialog.setVisible(true);
|
||||
indexDialog.setModal(true);
|
||||
}
|
||||
}//GEN-LAST:event_indexButtonActionPerformed
|
||||
|
||||
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.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javax.imageio.ImageIO;
|
||||
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.ContentViewerTag;
|
||||
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.ImageUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -805,10 +806,10 @@ class ReportHTML implements TableReportModule {
|
||||
|
||||
if(!imageTags.isEmpty()) {
|
||||
//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,
|
||||
imageTags, ImageTagsUtility.IconSize.MEDIUM, "png");
|
||||
BufferedImage thumbnailWithTags = ImageTagsUtil.getThumbnailWithTags(file,
|
||||
imageTags, ImageTagsUtil.IconSize.MEDIUM);
|
||||
|
||||
String fileName = org.sleuthkit.autopsy.coreutils.FileUtil.escapeFileName(file.getName());
|
||||
|
||||
@ -819,7 +820,7 @@ class ReportHTML implements TableReportModule {
|
||||
File fullImageWithTagsFile = Paths.get(fullImageWithTagsPath).toFile();
|
||||
|
||||
//Save images
|
||||
ImageIO.write(thumbnailImageWithTags, "png", thumbnailImageWithTagsFile);
|
||||
ImageIO.write(thumbnailWithTags, "png", thumbnailImageWithTagsFile);
|
||||
ImageIO.write(fullImageWithTags, "png", fullImageWithTagsFile);
|
||||
|
||||
thumbnailPath = THUMBS_REL_PATH + thumbnailImageWithTagsFile.getName();
|
||||
@ -828,7 +829,7 @@ class ReportHTML implements TableReportModule {
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Copyright 2014-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* 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
|
||||
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());
|
||||
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
@ -102,7 +103,7 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
|
||||
private final ExplorerManager explorerManager = new ExplorerManager();
|
||||
|
||||
private final TimeLineController controller;
|
||||
private TimeLineController controller;
|
||||
|
||||
/**
|
||||
* Lookup that will be exposed through the (Global Actions Context)
|
||||
@ -253,11 +254,12 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param controller The TimeLineController for this topcomponent.
|
||||
* Constructs a "shell" version of the top component for the Timeline
|
||||
* feature which has only Swing components, no controller, and no listeners.
|
||||
* 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();
|
||||
associateLookup(proxyLookup);
|
||||
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
|
||||
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ExternalViewerShortcutAction.EXTERNAL_VIEWER_SHORTCUT, "useExternalViewer"); //NON-NLS
|
||||
getActionMap().put("useExternalViewer", ExternalViewerShortcutAction.getInstance()); //NON-NLS
|
||||
this.controller = controller;
|
||||
|
||||
//create linked result and content views
|
||||
contentViewerPanel = new DataContentExplorerPanel();
|
||||
@ -278,6 +279,17 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer
|
||||
|
||||
dataResultPanel.open(); //get the explorermanager
|
||||
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);
|
||||
|
||||
|
@ -41,6 +41,9 @@ public final class OpenCvLoader {
|
||||
* Return whether or not the OpenCV library has been loaded.
|
||||
*
|
||||
* @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 {
|
||||
if (!OPEN_CV_LOADED) {
|
||||
|
@ -99,13 +99,14 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
|
||||
resultSet = None
|
||||
try:
|
||||
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():
|
||||
address = resultSet.getString("address") # may be phone number, or other addresses
|
||||
date = Long.valueOf(resultSet.getString("date")) / 1000
|
||||
read = resultSet.getInt("read") # may be unread = 0, read = 1
|
||||
subject = resultSet.getString("subject") # message subject
|
||||
body = resultSet.getString("body") # message body
|
||||
thread_id = "{0}_{1}".format(abstractFile.getId(), resultSet.getInt("thread_id"))
|
||||
attributes = ArrayList()
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); #create Message artifact and then add attributes from result set.
|
||||
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_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_THREAD_ID, general.MODULE_NAME, thread_id))
|
||||
|
||||
artifact.addAttributes(attributes)
|
||||
|
||||
|
@ -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
|
||||
@ -79,6 +81,7 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
|
||||
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()
|
||||
|
@ -1,3 +1,3 @@
|
||||
<project name="TSK_VERSION">
|
||||
<property name="TSK_VERSION" value="4.6.6"/>
|
||||
<property name="TSK_VERSION" value="4.6.7"/>
|
||||
</project>
|
||||
|
@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation"
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# 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
|
||||
# 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.
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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.
|
||||
# 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
|
||||
# generated HTML page (for example: .htm, .php, .asp).
|
||||
|
@ -4,10 +4,10 @@ app.title=Autopsy
|
||||
### lowercase version of above
|
||||
app.name=${branding.token}
|
||||
### 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=RELEASE
|
||||
build.type=DEVELOPMENT
|
||||
build.type=RELEASE
|
||||
#build.type=DEVELOPMENT
|
||||
|
||||
project.org.netbeans.progress=org-netbeans-api-progress
|
||||
project.org.sleuthkit.autopsy.experimental=Experimental
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
# NOTE: update_sleuthkit_version.pl updates this value and relies
|
||||
# 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...
|
||||
|
Loading…
x
Reference in New Issue
Block a user