mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 18:17:43 +00:00
Merge branch 'develop' of https://github.com/sleuthkit/autopsy into 3126-IngestEventsListenerChanges
This commit is contained in:
commit
b557bd8dca
@ -31,9 +31,20 @@ import javax.swing.JComponent;
|
|||||||
abstract class AbstractFileSearchFilter<T extends JComponent> implements FileSearchFilter {
|
abstract class AbstractFileSearchFilter<T extends JComponent> implements FileSearchFilter {
|
||||||
|
|
||||||
final private T component;
|
final private T component;
|
||||||
|
private String lastErrorMessage;
|
||||||
|
|
||||||
AbstractFileSearchFilter(T component) {
|
AbstractFileSearchFilter(T component) {
|
||||||
this.component = component;
|
this.component = component;
|
||||||
|
this.lastErrorMessage = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastError(String mes){
|
||||||
|
lastErrorMessage = mes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLastError(){
|
||||||
|
return this.lastErrorMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,4 +57,5 @@ MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected
|
|||||||
FileSearchPanel.searchButton.text=Search
|
FileSearchPanel.searchButton.text=Search
|
||||||
MimeTypePanel.mimeTypeCheckBox.text=MIME Type:
|
MimeTypePanel.mimeTypeCheckBox.text=MIME Type:
|
||||||
HashSearchPanel.md5CheckBox.text=MD5:
|
HashSearchPanel.md5CheckBox.text=MD5:
|
||||||
HashSearchPanel.emptyHashMsg.text=Must enter something for hash search.
|
HashSearchPanel.emptyHashMsg.text=Must enter something for hash search.
|
||||||
|
FileSearchPanel.errorLabel.text=\
|
||||||
|
@ -42,6 +42,7 @@ import javax.swing.SwingUtilities;
|
|||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters file date properties (modified/created/etc.. times)
|
* Filters file date properties (modified/created/etc.. times)
|
||||||
@ -79,25 +80,10 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
|
|||||||
String query = "NULL";
|
String query = "NULL";
|
||||||
DateSearchPanel panel = this.getComponent();
|
DateSearchPanel panel = this.getComponent();
|
||||||
|
|
||||||
// first, get the selected timeZone from the dropdown list
|
|
||||||
String tz = this.getComponent().getTimeZoneComboBox().getSelectedItem().toString();
|
|
||||||
String tzID = tz.substring(tz.indexOf(" ") + 1); // 1 index after the space is the ID
|
|
||||||
TimeZone selectedTZ = TimeZone.getTimeZone(tzID); //
|
|
||||||
|
|
||||||
// convert the date from the selected timezone to get the GMT
|
// convert the date from the selected timezone to get the GMT
|
||||||
long fromDate = 0;
|
long fromDate = 0;
|
||||||
String startDateValue = panel.getDateFromTextField().getText();
|
String startDateValue = panel.getDateFromTextField().getText();
|
||||||
Calendar startDate = null;
|
Calendar startDate = getCalendarDate(startDateValue);
|
||||||
try {
|
|
||||||
DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
|
|
||||||
sdf.setTimeZone(selectedTZ); // get the time in the selected timezone
|
|
||||||
Date temp = sdf.parse(startDateValue);
|
|
||||||
|
|
||||||
startDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); //NON-NLS
|
|
||||||
startDate.setTime(temp); // convert to GMT
|
|
||||||
} catch (ParseException ex) {
|
|
||||||
// for now, no need to show the error message to the user here
|
|
||||||
}
|
|
||||||
if (!startDateValue.isEmpty()) {
|
if (!startDateValue.isEmpty()) {
|
||||||
if (startDate != null) {
|
if (startDate != null) {
|
||||||
fromDate = startDate.getTimeInMillis() / 1000; // divided by 1000 because we want to get the seconds, not miliseconds
|
fromDate = startDate.getTimeInMillis() / 1000; // divided by 1000 because we want to get the seconds, not miliseconds
|
||||||
@ -106,31 +92,13 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
|
|||||||
|
|
||||||
long toDate = 0;
|
long toDate = 0;
|
||||||
String endDateValue = panel.getDateToTextField().getText();
|
String endDateValue = panel.getDateToTextField().getText();
|
||||||
Calendar endDate = null;
|
Calendar endDate = getCalendarDate(endDateValue);
|
||||||
try {
|
|
||||||
DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
|
|
||||||
sdf.setTimeZone(selectedTZ); // get the time in the selected timezone
|
|
||||||
Date temp2 = sdf.parse(endDateValue);
|
|
||||||
|
|
||||||
endDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); //NON-NLS
|
|
||||||
endDate.setTime(temp2); // convert to GMT
|
|
||||||
endDate.set(Calendar.HOUR, endDate.get(Calendar.HOUR) + 24); // get the next 24 hours
|
|
||||||
} catch (ParseException ex) {
|
|
||||||
// for now, no need to show the error message to the user here
|
|
||||||
}
|
|
||||||
if (!endDateValue.isEmpty()) {
|
if (!endDateValue.isEmpty()) {
|
||||||
if (endDate != null) {
|
if (endDate != null) {
|
||||||
toDate = endDate.getTimeInMillis() / 1000; // divided by 1000 because we want to get the seconds, not miliseconds
|
toDate = endDate.getTimeInMillis() / 1000; // divided by 1000 because we want to get the seconds, not miliseconds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If they put the dates in backwards, help them out.
|
|
||||||
if (fromDate > toDate) {
|
|
||||||
long temp = toDate;
|
|
||||||
toDate = fromDate;
|
|
||||||
fromDate = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean modifiedChecked = panel.getModifiedCheckBox().isSelected();
|
final boolean modifiedChecked = panel.getModifiedCheckBox().isSelected();
|
||||||
final boolean changedChecked = panel.getChangedCheckBox().isSelected();
|
final boolean changedChecked = panel.getChangedCheckBox().isSelected();
|
||||||
final boolean accessedChecked = panel.getAccessedCheckBox().isSelected();
|
final boolean accessedChecked = panel.getAccessedCheckBox().isSelected();
|
||||||
@ -206,14 +174,56 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
|
|||||||
return timeZones;
|
return timeZones;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TimeZone getSelectedTimeZone() {
|
||||||
|
String tz = this.getComponent().getTimeZoneComboBox().getSelectedItem().toString();
|
||||||
|
String tzID = tz.substring(tz.indexOf(" ") + 1); // 1 index after the space is the ID
|
||||||
|
TimeZone selectedTZ = TimeZone.getTimeZone(tzID); //
|
||||||
|
return selectedTZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Calendar getCalendarDate(String dateValue) {
|
||||||
|
TimeZone selectedTZ = getSelectedTimeZone();
|
||||||
|
Calendar inputDate = null;
|
||||||
|
try {
|
||||||
|
DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
|
||||||
|
sdf.setTimeZone(selectedTZ); // get the time in the selected timezone
|
||||||
|
Date temp = sdf.parse(dateValue);
|
||||||
|
|
||||||
|
inputDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); //NON-NLS
|
||||||
|
inputDate.setTime(temp); // convert to GMT
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
// for now, no need to show the error message to the user here
|
||||||
|
}
|
||||||
|
return inputDate;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addActionListener(ActionListener l) {
|
public void addActionListener(ActionListener l) {
|
||||||
getComponent().addActionListener(l);
|
getComponent().addActionListener(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Messages ({
|
||||||
|
"DateSearchFilter.errorMessage.endDateBeforeStartDate=The end date should be after the start date.",
|
||||||
|
"DateSearchFilter.errorMessage.noCheckboxSelected=At least one date type checkbox must be selected."
|
||||||
|
})
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
return this.getComponent().isValidSearch();
|
|
||||||
|
DateSearchPanel panel = this.getComponent();
|
||||||
|
Calendar startDate = getCalendarDate(panel.getDateFromTextField().getText());
|
||||||
|
Calendar endDate = getCalendarDate(panel.getDateToTextField().getText());
|
||||||
|
|
||||||
|
if ((startDate != null && startDate.after(endDate)) || (endDate != null && endDate.before(startDate))) {
|
||||||
|
setLastError(Bundle.DateSearchFilter_errorMessage_endDateBeforeStartDate());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!panel.isValidSearch()) {
|
||||||
|
setLastError(Bundle.DateSearchFilter_errorMessage_noCheckboxSelected());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,6 +149,7 @@
|
|||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JFormattedTextField" name="dateToTextField">
|
<Component class="javax.swing.JFormattedTextField" name="dateToTextField">
|
||||||
<Properties>
|
<Properties>
|
||||||
|
<Property name="editable" type="boolean" value="false"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="DateSearchPanel.dateToTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="DateSearchPanel.dateToTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
@ -208,6 +209,7 @@
|
|||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JFormattedTextField" name="dateFromTextField">
|
<Component class="javax.swing.JFormattedTextField" name="dateFromTextField">
|
||||||
<Properties>
|
<Properties>
|
||||||
|
<Property name="editable" type="boolean" value="false"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="DateSearchPanel.dateFromTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="DateSearchPanel.dateFromTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
|
@ -29,6 +29,8 @@ import javax.swing.JComboBox;
|
|||||||
import javax.swing.JFormattedTextField;
|
import javax.swing.JFormattedTextField;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
import javax.swing.JPopupMenu;
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subpanel with controls for file data filtering.
|
* Subpanel with controls for file data filtering.
|
||||||
@ -50,6 +52,7 @@ class DateSearchPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
dateFromTextField.setComponentPopupMenu(rightClickMenu);
|
dateFromTextField.setComponentPopupMenu(rightClickMenu);
|
||||||
dateToTextField.setComponentPopupMenu(rightClickMenu);
|
dateToTextField.setComponentPopupMenu(rightClickMenu);
|
||||||
|
|
||||||
ActionListener actList = new ActionListener() {
|
ActionListener actList = new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
@ -74,6 +77,41 @@ class DateSearchPanel extends javax.swing.JPanel {
|
|||||||
copyMenuItem.addActionListener(actList);
|
copyMenuItem.addActionListener(actList);
|
||||||
pasteMenuItem.addActionListener(actList);
|
pasteMenuItem.addActionListener(actList);
|
||||||
selectAllMenuItem.addActionListener(actList);
|
selectAllMenuItem.addActionListener(actList);
|
||||||
|
this.dateFromTextField.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.dateToTextField.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
this.setComponentsEnabled();
|
this.setComponentsEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +214,7 @@ class DateSearchPanel extends javax.swing.JPanel {
|
|||||||
selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.selectAllMenuItem.text")); // NOI18N
|
selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.selectAllMenuItem.text")); // NOI18N
|
||||||
rightClickMenu.add(selectAllMenuItem);
|
rightClickMenu.add(selectAllMenuItem);
|
||||||
|
|
||||||
|
dateToTextField.setEditable(false);
|
||||||
dateToTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateToTextField.text")); // NOI18N
|
dateToTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateToTextField.text")); // NOI18N
|
||||||
dateToTextField.addFocusListener(new java.awt.event.FocusAdapter() {
|
dateToTextField.addFocusListener(new java.awt.event.FocusAdapter() {
|
||||||
public void focusLost(java.awt.event.FocusEvent evt) {
|
public void focusLost(java.awt.event.FocusEvent evt) {
|
||||||
@ -197,6 +236,7 @@ class DateSearchPanel extends javax.swing.JPanel {
|
|||||||
jLabel3.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
jLabel3.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||||
jLabel3.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel3.text")); // NOI18N
|
jLabel3.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel3.text")); // NOI18N
|
||||||
|
|
||||||
|
dateFromTextField.setEditable(false);
|
||||||
dateFromTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateFromTextField.text")); // NOI18N
|
dateFromTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateFromTextField.text")); // NOI18N
|
||||||
dateFromTextField.addFocusListener(new java.awt.event.FocusAdapter() {
|
dateFromTextField.addFocusListener(new java.awt.event.FocusAdapter() {
|
||||||
public void focusLost(java.awt.event.FocusEvent evt) {
|
public void focusLost(java.awt.event.FocusEvent evt) {
|
||||||
@ -365,6 +405,7 @@ class DateSearchPanel extends javax.swing.JPanel {
|
|||||||
if (evt.getNewValue() instanceof Date) {
|
if (evt.getNewValue() instanceof Date) {
|
||||||
setToDate((Date) evt.getNewValue());
|
setToDate((Date) evt.getNewValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
}//GEN-LAST:event_dateToPopupChanged
|
}//GEN-LAST:event_dateToPopupChanged
|
||||||
|
|
||||||
private void dateCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateCheckBoxActionPerformed
|
private void dateCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateCheckBoxActionPerformed
|
||||||
@ -399,6 +440,7 @@ class DateSearchPanel extends javax.swing.JPanel {
|
|||||||
if (date != null) {
|
if (date != null) {
|
||||||
dateStringResult = dateFormat.format(date);
|
dateStringResult = dateFormat.format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
dateFromTextField.setText(dateStringResult);
|
dateFromTextField.setText(dateStringResult);
|
||||||
dateFromButtonCalendar.setTargetDate(date);
|
dateFromButtonCalendar.setTargetDate(date);
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,13 @@ interface FileSearchFilter {
|
|||||||
* @return Whether the panel has valid input for search.
|
* @return Whether the panel has valid input for search.
|
||||||
*/
|
*/
|
||||||
boolean isValid();
|
boolean isValid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the last error recorded during the call to isValid
|
||||||
|
*
|
||||||
|
* @return Description of why the filter is invalid
|
||||||
|
*/
|
||||||
|
String getLastError();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets predicate expression to include in the SQL filter expression
|
* Gets predicate expression to include in the SQL filter expression
|
||||||
|
@ -23,7 +23,9 @@
|
|||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="filterPanel" alignment="0" max="32767" attributes="0"/>
|
<Component id="filterPanel" alignment="0" max="32767" attributes="0"/>
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" alignment="1" attributes="0">
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="errorLabel" max="32767" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
|
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -32,9 +34,14 @@
|
|||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<Component id="filterPanel" max="32767" attributes="0"/>
|
<Component id="filterPanel" pref="266" max="32767" attributes="0"/>
|
||||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
<Group type="103" groupAlignment="1" attributes="0">
|
||||||
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
|
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
@ -63,6 +70,19 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="FileSearchPanel.searchButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="FileSearchPanel.searchButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="searchButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="errorLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||||
|
<Color blue="33" green="33" red="ff" type="rgb"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="FileSearchPanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -27,7 +27,6 @@ package org.sleuthkit.autopsy.filesearch;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
@ -111,13 +110,7 @@ class FileSearchPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addListenerToAll(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
search();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
searchButton.setEnabled(isValidSearch());
|
searchButton.setEnabled(isValidSearch());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,11 +123,13 @@ class FileSearchPanel extends javax.swing.JPanel {
|
|||||||
if (filter.isEnabled()) {
|
if (filter.isEnabled()) {
|
||||||
enabled = true;
|
enabled = true;
|
||||||
if (!filter.isValid()) {
|
if (!filter.isValid()) {
|
||||||
|
errorLabel.setText(filter.getLastError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errorLabel.setText("");
|
||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,6 +275,7 @@ class FileSearchPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
filterPanel = new javax.swing.JPanel();
|
filterPanel = new javax.swing.JPanel();
|
||||||
searchButton = new javax.swing.JButton();
|
searchButton = new javax.swing.JButton();
|
||||||
|
errorLabel = new javax.swing.JLabel();
|
||||||
|
|
||||||
setPreferredSize(new java.awt.Dimension(300, 300));
|
setPreferredSize(new java.awt.Dimension(300, 300));
|
||||||
|
|
||||||
@ -288,6 +284,14 @@ class FileSearchPanel extends javax.swing.JPanel {
|
|||||||
filterPanel.setLayout(new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS));
|
filterPanel.setLayout(new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS));
|
||||||
|
|
||||||
searchButton.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.searchButton.text")); // NOI18N
|
searchButton.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.searchButton.text")); // NOI18N
|
||||||
|
searchButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
searchButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
errorLabel.setForeground(new java.awt.Color(255, 51, 51));
|
||||||
|
errorLabel.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.errorLabel.text")); // NOI18N
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
@ -295,21 +299,31 @@ class FileSearchPanel extends javax.swing.JPanel {
|
|||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addContainerGap()
|
||||||
|
.addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(searchButton)
|
.addComponent(searchButton)
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE)
|
||||||
.addGap(0, 0, 0)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||||
.addComponent(searchButton)
|
.addComponent(searchButton)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(errorLabel)))
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
|
||||||
|
search();
|
||||||
|
}//GEN-LAST:event_searchButtonActionPerformed
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JLabel errorLabel;
|
||||||
private javax.swing.JPanel filterPanel;
|
private javax.swing.JPanel filterPanel;
|
||||||
private javax.swing.JButton searchButton;
|
private javax.swing.JButton searchButton;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.filesearch;
|
|||||||
|
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,7 +61,25 @@ class HashSearchFilter extends AbstractFileSearchFilter<HashSearchPanel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Messages({
|
||||||
|
"HashSearchFilter.errorMessage.emptyHash=Hash data is empty.",
|
||||||
|
"# {0} - hash data length", "HashSearchFilter.errorMessage.wrongLength=Input length({0}), doesn''t match the MD5 length(32).",
|
||||||
|
"HashSearchFilter.errorMessage.wrongCharacter=MD5 contains invalid hex characters."
|
||||||
|
})
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
return !this.getComponent().getSearchTextField().getText().isEmpty();
|
String inputHashData = this.getComponent().getSearchTextField().getText();
|
||||||
|
if (inputHashData.isEmpty()) {
|
||||||
|
setLastError(Bundle.HashSearchFilter_errorMessage_emptyHash());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (inputHashData.length() != 32) {
|
||||||
|
setLastError(Bundle.HashSearchFilter_errorMessage_wrongLength(inputHashData.length()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!inputHashData.matches("[0-9a-fA-F]+")) {
|
||||||
|
setLastError(Bundle.HashSearchFilter_errorMessage_wrongCharacter());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.filesearch;
|
|||||||
|
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.datamodel.TskData.FileKnown;
|
import org.sleuthkit.datamodel.TskData.FileKnown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,7 +86,14 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter<KnownStatusSearch
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Messages ({
|
||||||
|
"KnownStatusSearchFilter.errorMessage.noKnownStatusCheckboxSelected=At least one known status checkbox must be selected."
|
||||||
|
})
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
return this.getComponent().isValidSearch();
|
if (!this.getComponent().isValidSearch()) {
|
||||||
|
setLastError(Bundle.KnownStatusSearchFilter_errorMessage_noKnownStatusCheckboxSelected());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package org.sleuthkit.autopsy.filesearch;
|
package org.sleuthkit.autopsy.filesearch;
|
||||||
|
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter by mime type used in filter areas of file search by attribute.
|
* Filter by mime type used in filter areas of file search by attribute.
|
||||||
@ -42,7 +43,14 @@ class MimeTypeFilter extends AbstractFileSearchFilter<MimeTypePanel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Messages ({
|
||||||
|
"MimeTypeFilter.errorMessage.emptyMimeType=At least one MIME type must be selected."
|
||||||
|
})
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
return !this.getComponent().getMimeTypesSelected().isEmpty();
|
if(this.getComponent().getMimeTypesSelected().isEmpty()){
|
||||||
|
setLastError(Bundle.MimeTypeFilter_errorMessage_emptyMimeType());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.filesearch;
|
|||||||
|
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,7 +65,14 @@ class NameSearchFilter extends AbstractFileSearchFilter<NameSearchPanel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Messages ({
|
||||||
|
"NameSearchFilter.errorMessage.emtpyName=Please input a name to search."
|
||||||
|
})
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
return !this.getComponent().getSearchTextField().getText().isEmpty();
|
if(this.getComponent().getSearchTextField().getText().isEmpty()) {
|
||||||
|
setLastError(Bundle.NameSearchFilter_errorMessage_emtpyName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.filesearch;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,7 +75,23 @@ class SizeSearchFilter extends AbstractFileSearchFilter<SizeSearchPanel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Messages ({
|
||||||
|
"SizeSearchFilter.errorMessage.nonNegativeNumber=Input size data is a negative number.",
|
||||||
|
"SizeSearchFilter.errorMessage.notANumber=Input size data is not a number."
|
||||||
|
})
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
|
String input = this.getComponent().getSizeTextField().getText();
|
||||||
|
|
||||||
|
try {
|
||||||
|
int inputInt = Integer.parseInt(input);
|
||||||
|
if (inputInt < 0) {
|
||||||
|
setLastError(Bundle.SizeSearchFilter_errorMessage_nonNegativeNumber());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException | NullPointerException e) {
|
||||||
|
setLastError(Bundle.SizeSearchFilter_errorMessage_notANumber());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ import javax.swing.JCheckBox;
|
|||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JFormattedTextField;
|
import javax.swing.JFormattedTextField;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -65,6 +67,24 @@ class SizeSearchPanel extends javax.swing.JPanel {
|
|||||||
copyMenuItem.addActionListener(actList);
|
copyMenuItem.addActionListener(actList);
|
||||||
pasteMenuItem.addActionListener(actList);
|
pasteMenuItem.addActionListener(actList);
|
||||||
selectAllMenuItem.addActionListener(actList);
|
selectAllMenuItem.addActionListener(actList);
|
||||||
|
this.sizeTextField.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,8 +192,6 @@ public final class IngestMonitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logMemoryUsage();
|
logMemoryUsage();
|
||||||
logDiskSpaceUsage();
|
|
||||||
|
|
||||||
if (!enoughDiskSpace()) {
|
if (!enoughDiskSpace()) {
|
||||||
/*
|
/*
|
||||||
* Shut down ingest by cancelling all ingest jobs.
|
* Shut down ingest by cancelling all ingest jobs.
|
||||||
|
@ -33,7 +33,8 @@ import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile;
|
|||||||
*/
|
*/
|
||||||
class ProfilePanel extends IngestModuleGlobalSettingsPanel {
|
class ProfilePanel extends IngestModuleGlobalSettingsPanel {
|
||||||
|
|
||||||
@NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Description:",
|
@NbBundle.Messages({"ProfilePanel.title.text=Profile",
|
||||||
|
"ProfilePanel.profileDescLabel.text=Description:",
|
||||||
"ProfilePanel.profileNameLabel.text=Profile Name:",
|
"ProfilePanel.profileNameLabel.text=Profile Name:",
|
||||||
"ProfilePanel.newProfileText=NewEmptyProfile",
|
"ProfilePanel.newProfileText=NewEmptyProfile",
|
||||||
"ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named.",
|
"ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named.",
|
||||||
@ -50,6 +51,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel {
|
|||||||
*/
|
*/
|
||||||
ProfilePanel() {
|
ProfilePanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
setName(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.title.text"));
|
||||||
settings = new IngestJobSettings(NEW_PROFILE_NAME);
|
settings = new IngestJobSettings(NEW_PROFILE_NAME);
|
||||||
ingestSettingsPanel = new IngestJobSettingsPanel(settings);
|
ingestSettingsPanel = new IngestJobSettingsPanel(settings);
|
||||||
ingestSettingsPanel.setPastJobsButtonVisible(false);
|
ingestSettingsPanel.setPastJobsButtonVisible(false);
|
||||||
@ -59,6 +61,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel {
|
|||||||
|
|
||||||
ProfilePanel(IngestProfile selectedProfile) {
|
ProfilePanel(IngestProfile selectedProfile) {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
setName(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.title.text"));
|
||||||
profile = selectedProfile;
|
profile = selectedProfile;
|
||||||
profileDescArea.setText(profile.getDescription());
|
profileDescArea.setText(profile.getDescription());
|
||||||
profileNameField.setText(profile.getName());
|
profileNameField.setText(profile.getName());
|
||||||
|
@ -4,8 +4,6 @@ OpenIDE-Module-Short-Description=Interesting Files Identifier ingest module.
|
|||||||
OpenIDE-Module-Name=Interesting Files Identifier
|
OpenIDE-Module-Name=Interesting Files Identifier
|
||||||
OptionsCategory_Name_InterestingItemDefinitions=Interesting Files
|
OptionsCategory_Name_InterestingItemDefinitions=Interesting Files
|
||||||
OptionsCategory_Keywords_InterestingItemDefinitions=InterestingItemDefinitions
|
OptionsCategory_Keywords_InterestingItemDefinitions=InterestingItemDefinitions
|
||||||
OptionsCategory_Name_FileIngestFilterDefinitions=File Ingest Filter
|
|
||||||
OptionsCategory_Keywords_FileIngestFilterDefinitions=FileIngestFilterDefinitions
|
|
||||||
InterestingItemsIdentifierIngestModule.moduleName=Interesting Files Identifier
|
InterestingItemsIdentifierIngestModule.moduleName=Interesting Files Identifier
|
||||||
InterestingItemsIdentifierIngestModule.moduleDescription=Identifies interesting items as defined by interesting item rule sets.
|
InterestingItemsIdentifierIngestModule.moduleDescription=Identifies interesting items as defined by interesting item rule sets.
|
||||||
FilesSetPanel.interesting.title=Interesting Files Set
|
FilesSetPanel.interesting.title=Interesting Files Set
|
||||||
@ -45,7 +43,7 @@ FilesSetRulePanel.fileSizeCheck.text=File Size:
|
|||||||
FilesSetRulePanel.filesRadioButton.text=Files
|
FilesSetRulePanel.filesRadioButton.text=Files
|
||||||
FilesSetRulePanel.dirsRadioButton.text=Directories
|
FilesSetRulePanel.dirsRadioButton.text=Directories
|
||||||
FilesSetDefsPanel.interesting.setsListLabel.text=Rule Sets:
|
FilesSetDefsPanel.interesting.setsListLabel.text=Rule Sets:
|
||||||
FilesSetDefsPanel.ingest.setsListLabel.text=File Ingest Filters:
|
FilesSetDefsPanel.ingest.setsListLabel.text=File Filters:
|
||||||
FilesSetDefsPanel.interesting.jTextArea1.text=This module allows you to find files that match specified criteria. Each set has a list of rules, which will match on their chosen file characteristics. A file need only match one rule to be found.
|
FilesSetDefsPanel.interesting.jTextArea1.text=This module allows you to find files that match specified criteria. Each set has a list of rules, which will match on their chosen file characteristics. A file need only match one rule to be found.
|
||||||
FilesSetDefsPanel.ingest.jTextArea1.text=Add rules so that only a subset of the files in a data source are analyzed. Rules are organized into sets and only one set can be used at a time. A file need only match one rule to be analyzed.
|
FilesSetDefsPanel.ingest.jTextArea1.text=Add rules so that only a subset of the files in a data source are analyzed. Rules are organized into sets and only one set can be used at a time. A file need only match one rule to be analyzed.
|
||||||
FilesSetDefsPanel.interesting.editSetButton.text=Edit Set
|
FilesSetDefsPanel.interesting.editSetButton.text=Edit Set
|
||||||
|
@ -77,6 +77,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
|||||||
private final JButton okButton = new JButton("OK");
|
private final JButton okButton = new JButton("OK");
|
||||||
private final JButton cancelButton = new JButton("Cancel");
|
private final JButton cancelButton = new JButton("Cancel");
|
||||||
private final PANEL_TYPE panelType;
|
private final PANEL_TYPE panelType;
|
||||||
|
private final String filterDialogTitle;
|
||||||
private final String ruleDialogTitle;
|
private final String ruleDialogTitle;
|
||||||
private boolean canBeEnabled = true;
|
private boolean canBeEnabled = true;
|
||||||
|
|
||||||
@ -109,7 +110,8 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
|||||||
this.jLabel7.setVisible(false);
|
this.jLabel7.setVisible(false);
|
||||||
this.fileSizeUnitComboBox.setVisible(false);
|
this.fileSizeUnitComboBox.setVisible(false);
|
||||||
this.fileSizeSpinner.setVisible(false);
|
this.fileSizeSpinner.setVisible(false);
|
||||||
this.ruleDialogTitle = "FilesSetPanel.ingest.title";
|
this.filterDialogTitle = "FilesSetPanel.filter.title";
|
||||||
|
this.ruleDialogTitle = "FilesSetPanel.rule.title";
|
||||||
this.jLabel8.setVisible(false);
|
this.jLabel8.setVisible(false);
|
||||||
this.equalitySignComboBox.setVisible(false);
|
this.equalitySignComboBox.setVisible(false);
|
||||||
this.ignoreKnownFilesCheckbox.setVisible(false);
|
this.ignoreKnownFilesCheckbox.setVisible(false);
|
||||||
@ -124,13 +126,14 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
|||||||
org.openide.awt.Mnemonics.setLocalizedText(deleteSetButton, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingest.deleteSetButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(deleteSetButton, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingest.deleteSetButton.text")); // NOI18N
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingest.jLabel6.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingest.jLabel6.text")); // NOI18N
|
||||||
} else {
|
} else {
|
||||||
|
this.filterDialogTitle = "FilesSetPanel.interesting.title";
|
||||||
this.ruleDialogTitle = "FilesSetPanel.interesting.title";
|
this.ruleDialogTitle = "FilesSetPanel.interesting.title";
|
||||||
this.ingoreUnallocCheckbox.setVisible(false);
|
this.ingoreUnallocCheckbox.setVisible(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({"FilesSetDefsPanel.Interesting.Title=Global Interesting Items Settings",
|
@NbBundle.Messages({"FilesSetDefsPanel.Interesting.Title=Global Interesting Items Settings",
|
||||||
"FilesSetDefsPanel.Ingest.Title=File Ingest Filter Settings"})
|
"FilesSetDefsPanel.Ingest.Title=File Filter Settings"})
|
||||||
private void customInit() {
|
private void customInit() {
|
||||||
if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) {
|
if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) {
|
||||||
setName(Bundle.FilesSetDefsPanel_Ingest_Title());
|
setName(Bundle.FilesSetDefsPanel_Ingest_Title());
|
||||||
@ -408,7 +411,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
|||||||
// feedback when isValidDefinition() is called.
|
// feedback when isValidDefinition() is called.
|
||||||
int option = JOptionPane.OK_OPTION;
|
int option = JOptionPane.OK_OPTION;
|
||||||
do {
|
do {
|
||||||
option = JOptionPane.showConfirmDialog(null, panel, NbBundle.getMessage(FilesSetPanel.class, ruleDialogTitle), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
option = JOptionPane.showConfirmDialog(null, panel, NbBundle.getMessage(FilesSetPanel.class, filterDialogTitle), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||||
} while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition());
|
} while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition());
|
||||||
|
|
||||||
// While adding new ruleset(selectedSet == null), if rule set with same name already exists, do not add to the filesSets hashMap.
|
// While adding new ruleset(selectedSet == null), if rule set with same name already exists, do not add to the filesSets hashMap.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2014-2016 Basis Technology Corp.
|
* Copyright 2014-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TY
|
|||||||
*/
|
*/
|
||||||
public class FilesSetPanel extends javax.swing.JPanel {
|
public class FilesSetPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
@NbBundle.Messages({"FilesSetPanel.ingest.title=File Ingest Filter", "FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filters...", "FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named."})
|
@NbBundle.Messages({"FilesSetPanel.filter.title=File Filter", "FilesSetPanel.rule.title=File Filter Rule", "FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filters...", "FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named."})
|
||||||
|
|
||||||
private static final String CREATE_NEW_FILE_INGEST_FILTER = Bundle.FilesSetPanel_ingest_createNewFilter();
|
private static final String CREATE_NEW_FILE_INGEST_FILTER = Bundle.FilesSetPanel_ingest_createNewFilter();
|
||||||
private final String mustBeNamedErrorText;
|
private final String mustBeNamedErrorText;
|
||||||
|
@ -44,6 +44,7 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.Account;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -174,7 +175,14 @@ class TableReportGenerator {
|
|||||||
* does not require a artifact name, so we make a synthetic
|
* does not require a artifact name, so we make a synthetic
|
||||||
* compund name by appending a ":" and the account type.
|
* compund name by appending a ":" and the account type.
|
||||||
*/
|
*/
|
||||||
final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountType;
|
String accountDisplayname = accountType;
|
||||||
|
for (Account.Type acct : Account.Type.values()) {
|
||||||
|
if (acct.equals(Account.Type.valueOf(accountType))) {
|
||||||
|
accountDisplayname = acct.getDisplayName();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountDisplayname;
|
||||||
writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountType)), type, compundDataTypeName, comment);
|
writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountType)), type, compundDataTypeName, comment);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager;
|
|||||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel;
|
import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel;
|
||||||
import org.sleuthkit.datamodel.TagName;
|
import org.sleuthkit.datamodel.TagName;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instances of this class are used to configure the report module plug in that
|
* Instances of this class are used to configure the report module plug in that
|
||||||
* provides a convenient way to add content hashes to hash set databases.
|
* provides a convenient way to add content hashes to hash set databases.
|
||||||
@ -94,9 +93,11 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel {
|
|||||||
public void mousePressed(MouseEvent evt) {
|
public void mousePressed(MouseEvent evt) {
|
||||||
JList<?> list = (JList) evt.getSource();
|
JList<?> list = (JList) evt.getSource();
|
||||||
int index = list.locationToIndex(evt.getPoint());
|
int index = list.locationToIndex(evt.getPoint());
|
||||||
String value = tagsNamesListModel.getElementAt(index);
|
if (index > -1) {
|
||||||
tagNameSelections.put(value, !tagNameSelections.get(value));
|
String value = tagsNamesListModel.getElementAt(index);
|
||||||
list.repaint();
|
tagNameSelections.put(value, !tagNameSelections.get(value));
|
||||||
|
list.repaint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-2017 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.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A runnable that adds an archive data source as well as data sources
|
||||||
|
* contained in the archive to the case database.
|
||||||
|
*/
|
||||||
|
class AddArchiveTask implements Runnable {
|
||||||
|
|
||||||
|
private final Logger logger = Logger.getLogger(AddArchiveTask.class.getName());
|
||||||
|
private final String deviceId;
|
||||||
|
private final String archivePath;
|
||||||
|
private final DataSourceProcessorProgressMonitor progressMonitor;
|
||||||
|
private final DataSourceProcessorCallback callback;
|
||||||
|
private boolean criticalErrorOccurred;
|
||||||
|
|
||||||
|
private static final String ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR = "Archive Extractor";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a runnable task that adds an archive as well as data sources
|
||||||
|
* contained in the archive to the case database.
|
||||||
|
*
|
||||||
|
* @param deviceId An ASCII-printable identifier for the device associated
|
||||||
|
* with the data source that is intended to be unique across multiple cases
|
||||||
|
* (e.g., a UUID).
|
||||||
|
* @param archivePath Path to the archive file.
|
||||||
|
* @param progressMonitor Progress monitor to report progress during
|
||||||
|
* processing.
|
||||||
|
* @param callback Callback to call when processing is done.
|
||||||
|
*/
|
||||||
|
AddArchiveTask(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.archivePath = archivePath;
|
||||||
|
this.callback = callback;
|
||||||
|
this.progressMonitor = progressMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the archive to the case database.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
List<String> errorMessages = new ArrayList<>();
|
||||||
|
List<Content> newDataSources = new ArrayList<>();
|
||||||
|
DataSourceProcessorCallback.DataSourceProcessorResult result;
|
||||||
|
if (!ArchiveUtil.isArchive(Paths.get(archivePath))) {
|
||||||
|
criticalErrorOccurred = true;
|
||||||
|
logger.log(Level.SEVERE, String.format("Input data source is not a valid datasource: %s", archivePath)); //NON-NLS
|
||||||
|
errorMessages.add("Input data source is not a valid datasource: " + archivePath);
|
||||||
|
result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
|
||||||
|
callback.done(result, errorMessages, newDataSources);
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract the archive and pass the extracted folder as input
|
||||||
|
Path destinationFolder = Paths.get("");
|
||||||
|
try {
|
||||||
|
Case currentCase = Case.getCurrentCase();
|
||||||
|
|
||||||
|
// get file name without full path or extension
|
||||||
|
String dataSourceFileNameNoExt = FilenameUtils.getBaseName(archivePath);
|
||||||
|
|
||||||
|
// create folder to extract archive to
|
||||||
|
destinationFolder = Paths.get(currentCase.getModuleDirectory(), ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR, dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp());
|
||||||
|
destinationFolder.toFile().mkdirs();
|
||||||
|
|
||||||
|
// extract contents of ZIP archive into destination folder
|
||||||
|
//ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString());
|
||||||
|
|
||||||
|
// do processing
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
criticalErrorOccurred = true;
|
||||||
|
errorMessages.add(ex.getMessage());
|
||||||
|
logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS
|
||||||
|
} finally {
|
||||||
|
if (criticalErrorOccurred) {
|
||||||
|
result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
|
||||||
|
} else if (!errorMessages.isEmpty()) {
|
||||||
|
result = DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS;
|
||||||
|
} else {
|
||||||
|
result = DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS;
|
||||||
|
}
|
||||||
|
callback.done(result, errorMessages, newDataSources);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempts to cancel adding the archive to the case database.
|
||||||
|
*/
|
||||||
|
public void cancelTask() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-2017 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.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A "callback" that collects the results of running a data source processor on
|
||||||
|
* a data source and unblocks the job processing thread when the data source
|
||||||
|
* processor finishes running in its own thread.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
class AddDataSourceCallback extends DataSourceProcessorCallback {
|
||||||
|
|
||||||
|
private final Case caseForJob;
|
||||||
|
private final DataSource dataSourceInfo;
|
||||||
|
private final UUID taskId;
|
||||||
|
private final Object lock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a "callback" that collects the results of running a data
|
||||||
|
* source processor on a data source and unblocks the job processing thread
|
||||||
|
* when the data source processor finishes running in its own thread.
|
||||||
|
*
|
||||||
|
* @param caseForJob The case for the current job.
|
||||||
|
* @param dataSourceInfo The data source
|
||||||
|
* @param taskId The task id to associate with ingest job events.
|
||||||
|
*/
|
||||||
|
AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId, Object lock) {
|
||||||
|
this.caseForJob = caseForJob;
|
||||||
|
this.dataSourceInfo = dataSourceInfo;
|
||||||
|
this.taskId = taskId;
|
||||||
|
this.lock = lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the data source processor when it finishes running in its own
|
||||||
|
* thread.
|
||||||
|
*
|
||||||
|
* @param result The result code for the processing of the data source.
|
||||||
|
* @param errorMessages Any error messages generated during the processing
|
||||||
|
* of the data source.
|
||||||
|
* @param dataSourceContent The content produced by processing the data
|
||||||
|
* source.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSourceContent) {
|
||||||
|
if (!dataSourceContent.isEmpty()) {
|
||||||
|
caseForJob.notifyDataSourceAdded(dataSourceContent.get(0), taskId);
|
||||||
|
} else {
|
||||||
|
caseForJob.notifyFailedAddingDataSource(taskId);
|
||||||
|
}
|
||||||
|
dataSourceInfo.setDataSourceProcessorOutput(result, errorMessages, dataSourceContent);
|
||||||
|
dataSourceContent.addAll(dataSourceContent);
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the data source processor when it finishes running in its own
|
||||||
|
* thread, if that thread is the AWT (Abstract Window Toolkit) event
|
||||||
|
* dispatch thread (EDT).
|
||||||
|
*
|
||||||
|
* @param result The result code for the processing of the data source.
|
||||||
|
* @param errorMessages Any error messages generated during the processing
|
||||||
|
* of the data source.
|
||||||
|
* @param dataSourceContent The content produced by processing the data
|
||||||
|
* source.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSources) {
|
||||||
|
done(result, errorMessages, dataSources);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-2017 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.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.UUID;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
|
import org.openide.util.lookup.ServiceProviders;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
|
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data source processor that handles archive files. Implements the
|
||||||
|
* DataSourceProcessor service provider interface to allow integration with the
|
||||||
|
* add data source wizard. It also provides a run method overload to allow it to
|
||||||
|
* be used independently of the wizard.
|
||||||
|
*/
|
||||||
|
//@ServiceProviders(value={
|
||||||
|
// @ServiceProvider(service=DataSourceProcessor.class),
|
||||||
|
// @ServiceProvider(service=AutoIngestDataSourceProcessor.class)}
|
||||||
|
//)
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"ArchiveDSP.dsType.text=Archive file"})
|
||||||
|
public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor {
|
||||||
|
|
||||||
|
private final static String DATA_SOURCE_TYPE = Bundle.ArchiveDSP_dsType_text();
|
||||||
|
|
||||||
|
private final ArchiveFilePanel configPanel;
|
||||||
|
private String deviceId;
|
||||||
|
private String archivePath;
|
||||||
|
private boolean setDataSourceOptionsCalled;
|
||||||
|
|
||||||
|
private AddArchiveTask addArchiveTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an archive data source processor that
|
||||||
|
* implements the DataSourceProcessor service provider interface to allow
|
||||||
|
* integration with the add data source wizard. It also provides a run
|
||||||
|
* method overload to allow it to be used independently of the wizard.
|
||||||
|
*/
|
||||||
|
public ArchiveExtractorDSProcessor() {
|
||||||
|
configPanel = ArchiveFilePanel.createInstance(ArchiveExtractorDSProcessor.class.getName(), ArchiveUtil.getArchiveFilters());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
|
||||||
|
// check whether this is an archive
|
||||||
|
if (ArchiveUtil.isArchive(dataSourcePath)){
|
||||||
|
// return "high confidence" value
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException {
|
||||||
|
run(deviceId, dataSourcePath.toString(), progressMonitor, callBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDataSourceType() {
|
||||||
|
return DATA_SOURCE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the panel that allows a user to select a data source and do any
|
||||||
|
* configuration required by the data source. The panel is less than 544
|
||||||
|
* pixels wide and less than 173 pixels high.
|
||||||
|
*
|
||||||
|
* @return A selection and configuration panel for this data source
|
||||||
|
* processor.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public JPanel getPanel() {
|
||||||
|
configPanel.readSettings();
|
||||||
|
configPanel.select();
|
||||||
|
return configPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the settings in the selection and configuration panel
|
||||||
|
* are valid and complete.
|
||||||
|
*
|
||||||
|
* @return True if the settings are valid and complete and the processor is
|
||||||
|
* ready to have its run method called, false otherwise.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isPanelValid() {
|
||||||
|
return configPanel.validatePanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a data source to the case database using a background task in a
|
||||||
|
* separate thread and the settings provided by the selection and
|
||||||
|
* configuration panel. Returns as soon as the background task is started.
|
||||||
|
* The background task uses a callback object to signal task completion and
|
||||||
|
* return results.
|
||||||
|
*
|
||||||
|
* This method should not be called unless isPanelValid returns true.
|
||||||
|
*
|
||||||
|
* @param progressMonitor Progress monitor that will be used by the
|
||||||
|
* background task to report progress.
|
||||||
|
* @param callback Callback that will be used by the background task
|
||||||
|
* to return results.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||||
|
if (!setDataSourceOptionsCalled) {
|
||||||
|
configPanel.storeSettings();
|
||||||
|
deviceId = UUID.randomUUID().toString();
|
||||||
|
archivePath = configPanel.getContentPaths();
|
||||||
|
}
|
||||||
|
run(deviceId, archivePath, progressMonitor, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a data source to the case database using a background task in a
|
||||||
|
* separate thread and the given settings instead of those provided by the
|
||||||
|
* selection and configuration panel. Returns as soon as the background task
|
||||||
|
* is started and uses the callback object to signal task completion and
|
||||||
|
* return results.
|
||||||
|
*
|
||||||
|
* @param deviceId An ASCII-printable identifier for the device
|
||||||
|
* associated with the data source that is
|
||||||
|
* intended to be unique across multiple cases
|
||||||
|
* (e.g., a UUID).
|
||||||
|
* @param archivePath Path to the archive file.
|
||||||
|
* @param progressMonitor Progress monitor for reporting progress
|
||||||
|
* during processing.
|
||||||
|
* @param callback Callback to call when processing is done.
|
||||||
|
*/
|
||||||
|
public void run(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||||
|
addArchiveTask = new AddArchiveTask(deviceId, archivePath, progressMonitor, callback);
|
||||||
|
new Thread(addArchiveTask).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests cancellation of the background task that adds a data source to
|
||||||
|
* the case database, after the task is started using the run method. This
|
||||||
|
* is a "best effort" cancellation, with no guarantees that the case
|
||||||
|
* database will be unchanged. If cancellation succeeded, the list of new
|
||||||
|
* data sources returned by the background task will be empty.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
if (null != addArchiveTask) {
|
||||||
|
addArchiveTask.cancelTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
deviceId = null;
|
||||||
|
archivePath = null;
|
||||||
|
configPanel.reset();
|
||||||
|
setDataSourceOptionsCalled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the contents of a ZIP archive submitted as a data source to a
|
||||||
|
* subdirectory of the auto ingest module output directory.
|
||||||
|
*
|
||||||
|
* @throws IOException if there is a problem extracting the data source from
|
||||||
|
* the archive.
|
||||||
|
|
||||||
|
private static Path extractDataSource(Path outputDirectoryPath, Path dataSourcePath) throws IOException {
|
||||||
|
String dataSourceFileNameNoExt = FilenameUtils.removeExtension(dataSourcePath.getFileName().toString());
|
||||||
|
Path destinationFolder = Paths.get(outputDirectoryPath.toString(),
|
||||||
|
AUTO_INGEST_MODULE_OUTPUT_DIR,
|
||||||
|
dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp());
|
||||||
|
Files.createDirectories(destinationFolder);
|
||||||
|
|
||||||
|
int BUFFER_SIZE = 524288; // Read/write 500KB at a time
|
||||||
|
File sourceZipFile = dataSourcePath.toFile();
|
||||||
|
ZipFile zipFile;
|
||||||
|
zipFile = new ZipFile(sourceZipFile, ZipFile.OPEN_READ);
|
||||||
|
Enumeration<? extends ZipEntry> zipFileEntries = zipFile.entries();
|
||||||
|
try {
|
||||||
|
while (zipFileEntries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = zipFileEntries.nextElement();
|
||||||
|
String currentEntry = entry.getName();
|
||||||
|
File destFile = new File(destinationFolder.toString(), currentEntry);
|
||||||
|
destFile = new File(destinationFolder.toString(), destFile.getName());
|
||||||
|
File destinationParent = destFile.getParentFile();
|
||||||
|
destinationParent.mkdirs();
|
||||||
|
if (!entry.isDirectory()) {
|
||||||
|
BufferedInputStream is = new BufferedInputStream(zipFile.getInputStream(entry));
|
||||||
|
int currentByte;
|
||||||
|
byte data[] = new byte[BUFFER_SIZE];
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(destFile); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
|
||||||
|
currentByte = is.read(data, 0, BUFFER_SIZE);
|
||||||
|
while (currentByte != -1) {
|
||||||
|
dest.write(data, 0, currentByte);
|
||||||
|
currentByte = is.read(data, 0, BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
zipFile.close();
|
||||||
|
}
|
||||||
|
return destinationFolder;
|
||||||
|
} */
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<Properties>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[0, 65]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[403, 65]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<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"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Component id="pathTextField" max="32767" attributes="0"/>
|
||||||
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
|
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="errorLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace min="0" pref="277" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
|
||||||
|
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JLabel" name="pathLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="ArchiveFilePanel.pathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="browseButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="ArchiveFilePanel.browseButton.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="browseButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JTextField" name="pathTextField">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="ArchiveFilePanel.pathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="errorLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||||
|
<Color blue="0" green="0" red="ff" type="rgb"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="ArchiveFilePanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-2017 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.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import static org.sleuthkit.autopsy.experimental.autoingest.Bundle.*;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.DriveUtils;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.PathValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel for adding an archive file which is supported by 7zip library (e.g.
|
||||||
|
* "zip", "rar", "arj", "7z", "7zip", "gzip, etc). Allows the user to select a
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
class ArchiveFilePanel extends JPanel implements DocumentListener {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ArchiveFilePanel.class.getName());
|
||||||
|
private static final String PROP_LAST_ARCHIVE_PATH = "LBL_LastImage_PATH"; //NON-NLS
|
||||||
|
|
||||||
|
private final JFileChooser fileChooser = new JFileChooser();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Externally supplied name is used to store settings
|
||||||
|
*/
|
||||||
|
private final String contextName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new form ArchiveFilePanel
|
||||||
|
*
|
||||||
|
* @param context A string context name used to read/store last
|
||||||
|
* used settings.
|
||||||
|
* @param fileChooserFilters A list of filters to be used with the
|
||||||
|
* FileChooser.
|
||||||
|
*/
|
||||||
|
private ArchiveFilePanel(String context, List<FileFilter> fileChooserFilters) {
|
||||||
|
this.contextName = context;
|
||||||
|
initComponents();
|
||||||
|
|
||||||
|
errorLabel.setVisible(false);
|
||||||
|
|
||||||
|
fileChooser.setDragEnabled(false);
|
||||||
|
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||||
|
fileChooser.setMultiSelectionEnabled(false);
|
||||||
|
fileChooserFilters.forEach(fileChooser::addChoosableFileFilter);
|
||||||
|
if (fileChooserFilters.isEmpty() == false) {
|
||||||
|
fileChooser.setFileFilter(fileChooserFilters.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns an instance of a ArchiveFilePanel.
|
||||||
|
*
|
||||||
|
* @param context A string context name used to read/store last
|
||||||
|
* used settings.
|
||||||
|
* @param fileChooserFilters A list of filters to be used with the
|
||||||
|
* FileChooser.
|
||||||
|
*
|
||||||
|
* @return instance of the ArchiveFilePanel
|
||||||
|
*/
|
||||||
|
public static synchronized ArchiveFilePanel createInstance(String context, List<FileFilter> fileChooserFilters) {
|
||||||
|
ArchiveFilePanel instance = new ArchiveFilePanel(context, fileChooserFilters);
|
||||||
|
// post-constructor initialization of listener support without leaking references of uninitialized objects
|
||||||
|
instance.pathTextField.getDocument().addDocumentListener(instance);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
pathLabel = new javax.swing.JLabel();
|
||||||
|
browseButton = new javax.swing.JButton();
|
||||||
|
pathTextField = new javax.swing.JTextField();
|
||||||
|
errorLabel = new javax.swing.JLabel();
|
||||||
|
|
||||||
|
setMinimumSize(new java.awt.Dimension(0, 65));
|
||||||
|
setPreferredSize(new java.awt.Dimension(403, 65));
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.pathLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.browseButton.text")); // NOI18N
|
||||||
|
browseButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
browseButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pathTextField.setText(org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.pathTextField.text")); // NOI18N
|
||||||
|
|
||||||
|
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.errorLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
|
this.setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addComponent(pathTextField)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
|
.addComponent(browseButton)
|
||||||
|
.addGap(2, 2, 2))
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(pathLabel)
|
||||||
|
.addComponent(errorLabel))
|
||||||
|
.addGap(0, 277, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addComponent(pathLabel)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(browseButton)
|
||||||
|
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
|
.addGap(3, 3, 3)
|
||||||
|
.addComponent(errorLabel)
|
||||||
|
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
|
||||||
|
String oldText = getContentPaths();
|
||||||
|
// set the current directory of the FileChooser if the ArchivePath Field is valid
|
||||||
|
File currentDir = new File(oldText);
|
||||||
|
if (currentDir.exists()) {
|
||||||
|
fileChooser.setCurrentDirectory(currentDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
||||||
|
String path = fileChooser.getSelectedFile().getPath();
|
||||||
|
setContentPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHelper();
|
||||||
|
}//GEN-LAST:event_browseButtonActionPerformed
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JButton browseButton;
|
||||||
|
private javax.swing.JLabel errorLabel;
|
||||||
|
private javax.swing.JLabel pathLabel;
|
||||||
|
private javax.swing.JTextField pathTextField;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path of the user selected archive.
|
||||||
|
*
|
||||||
|
* @return the archive path
|
||||||
|
*/
|
||||||
|
public String getContentPaths() {
|
||||||
|
return pathTextField.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the path of the archive file.
|
||||||
|
*
|
||||||
|
* @param s path of the archive file
|
||||||
|
*/
|
||||||
|
public void setContentPath(String s) {
|
||||||
|
pathTextField.setText(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
//reset the UI elements to default
|
||||||
|
pathTextField.setText(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we enable the next button of the wizard?
|
||||||
|
*
|
||||||
|
* @return true if a proper archive has been selected, false otherwise
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages("DataSourceOnCDriveError.text=Warning: Path to multi-user data source is on \"C:\" drive")
|
||||||
|
public boolean validatePanel() {
|
||||||
|
errorLabel.setVisible(false);
|
||||||
|
String path = getContentPaths();
|
||||||
|
if (StringUtils.isBlank(path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// display warning if there is one (but don't disable "next" button)
|
||||||
|
if (false == PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) {
|
||||||
|
errorLabel.setVisible(true);
|
||||||
|
errorLabel.setText(Bundle.DataSourceOnCDriveError_text());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new File(path).isFile()
|
||||||
|
|| DriveUtils.isPhysicalDrive(path)
|
||||||
|
|| DriveUtils.isPartition(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void storeSettings() {
|
||||||
|
String archivePathName = getContentPaths();
|
||||||
|
if (null != archivePathName) {
|
||||||
|
String archivePath = archivePathName.substring(0, archivePathName.lastIndexOf(File.separator) + 1);
|
||||||
|
ModuleSettings.setConfigSetting(contextName, PROP_LAST_ARCHIVE_PATH, archivePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readSettings() {
|
||||||
|
String lastArchivePath = ModuleSettings.getConfigSetting(contextName, PROP_LAST_ARCHIVE_PATH);
|
||||||
|
if (StringUtils.isNotBlank(lastArchivePath)) {
|
||||||
|
setContentPath(lastArchivePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
updateHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
updateHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
updateHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update functions are called by the pathTextField which has this set as
|
||||||
|
* it's DocumentEventListener. Each update function fires a property change
|
||||||
|
* to be caught by the parent panel.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({"ArchiveFilePanel.moduleErr=Module Error",
|
||||||
|
"ArchiveFilePanel.moduleErr.msg=A module caused an error listening to ArchiveFilePanel updates."
|
||||||
|
+ " See log to determine which module. Some data could be incomplete.\n"})
|
||||||
|
private void updateHelper() {
|
||||||
|
try {
|
||||||
|
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "ArchiveFilePanel listener threw exception", e); //NON-NLS
|
||||||
|
MessageNotifyUtil.Notify.error(ArchiveFilePanel_moduleErr(), ArchiveFilePanel_moduleErr_msg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the focus to the pathTextField.
|
||||||
|
*/
|
||||||
|
public void select() {
|
||||||
|
pathTextField.requestFocusInWindow();
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,9 @@ import java.io.RandomAccessFile;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javax.swing.filechooser.FileFilter;
|
||||||
import net.sf.sevenzipjbinding.ISequentialOutStream;
|
import net.sf.sevenzipjbinding.ISequentialOutStream;
|
||||||
import net.sf.sevenzipjbinding.ISevenZipInArchive;
|
import net.sf.sevenzipjbinding.ISevenZipInArchive;
|
||||||
import net.sf.sevenzipjbinding.SevenZip;
|
import net.sf.sevenzipjbinding.SevenZip;
|
||||||
@ -35,18 +37,46 @@ import net.sf.sevenzipjbinding.SevenZipNativeInitializationException;
|
|||||||
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
|
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
|
||||||
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
|
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
|
||||||
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
|
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of utilities that handles archive file extraction. Uses 7zip library.
|
* Set of utilities that handles archive file extraction. Uses 7zip library.
|
||||||
*/
|
*/
|
||||||
final class ArchiveUtil {
|
final class ArchiveUtil {
|
||||||
|
|
||||||
static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // NON-NLS
|
private static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // NON-NLS
|
||||||
|
private static final List<String> ARCHIVE_EXTS = Arrays.asList(".zip", ".rar", ".arj", ".7z", ".7zip", ".gzip", ".gz", ".bzip2", ".tar", ".tgz"); //NON-NLS
|
||||||
|
@NbBundle.Messages("GeneralFilter.archiveDesc.text=Archive Files (.zip, .rar, .arj, .7z, .7zip, .gzip, .gz, .bzip2, .tar, .tgz)")
|
||||||
|
private static final String ARCHIVE_DESC = Bundle.GeneralFilter_archiveDesc_text();
|
||||||
|
private static final GeneralFilter SEVEN_ZIP_FILTER = new GeneralFilter(ARCHIVE_EXTS, ARCHIVE_DESC);
|
||||||
|
private static final List<FileFilter> ARCHIVE_FILTERS = new ArrayList<>();
|
||||||
|
static {
|
||||||
|
ARCHIVE_FILTERS.add(SEVEN_ZIP_FILTER);
|
||||||
|
}
|
||||||
|
|
||||||
private ArchiveUtil() {
|
private ArchiveUtil() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static List<FileFilter> getArchiveFilters() {
|
||||||
|
return ARCHIVE_FILTERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isArchive(Path dataSourcePath) {
|
||||||
|
String fileName = dataSourcePath.getFileName().toString();
|
||||||
|
// check whether it's a zip archive file that can be extracted
|
||||||
|
return isAcceptedByFiler(new File(fileName), ARCHIVE_FILTERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAcceptedByFiler(File file, List<FileFilter> filters) {
|
||||||
|
for (FileFilter filter : filters) {
|
||||||
|
if (filter.accept(file)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum of mime types which support archive extraction
|
* Enum of mime types which support archive extraction
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +37,6 @@ import java.time.Duration;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
@ -59,9 +58,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
||||||
@ -101,7 +97,6 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
|||||||
import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
|
import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleError;
|
import org.sleuthkit.autopsy.ingest.IngestModuleError;
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An auto ingest manager is responsible for processing auto ingest jobs defined
|
* An auto ingest manager is responsible for processing auto ingest jobs defined
|
||||||
@ -1454,7 +1449,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
*/
|
*/
|
||||||
private final class JobProcessingTask implements Runnable {
|
private final class JobProcessingTask implements Runnable {
|
||||||
|
|
||||||
private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest";
|
|
||||||
private final Object ingestLock;
|
private final Object ingestLock;
|
||||||
private final Object pauseLock;
|
private final Object pauseLock;
|
||||||
@GuardedBy("pauseLock")
|
@GuardedBy("pauseLock")
|
||||||
@ -2217,7 +2211,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataSource dataSource = identifyDataSource(caseForJob);
|
DataSource dataSource = identifyDataSource();
|
||||||
if (null == dataSource) {
|
if (null == dataSource) {
|
||||||
currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now()));
|
currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now()));
|
||||||
return;
|
return;
|
||||||
@ -2270,7 +2264,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
* interrupted while blocked, i.e.,
|
* interrupted while blocked, i.e.,
|
||||||
* if auto ingest is shutting down.
|
* if auto ingest is shutting down.
|
||||||
*/
|
*/
|
||||||
private DataSource identifyDataSource(Case caseForJob) throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException {
|
private DataSource identifyDataSource() throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException {
|
||||||
Manifest manifest = currentJob.getManifest();
|
Manifest manifest = currentJob.getManifest();
|
||||||
Path manifestPath = manifest.getFilePath();
|
Path manifestPath = manifest.getFilePath();
|
||||||
SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath);
|
SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath);
|
||||||
@ -2289,7 +2283,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
String deviceId = manifest.getDeviceId();
|
String deviceId = manifest.getDeviceId();
|
||||||
return new DataSource(deviceId, dataSourcePath);
|
return new DataSource(deviceId, dataSourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passes the data source for the current job through a data source
|
* Passes the data source for the current job through a data source
|
||||||
* processor that adds it to the case database.
|
* processor that adds it to the case database.
|
||||||
@ -2312,28 +2306,21 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath);
|
SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath);
|
||||||
currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now()));
|
currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now()));
|
||||||
UUID taskId = UUID.randomUUID();
|
UUID taskId = UUID.randomUUID();
|
||||||
DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId);
|
DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock);
|
||||||
DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor();
|
DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor();
|
||||||
Path caseDirectoryPath = currentJob.getCaseDirectoryPath();
|
Path caseDirectoryPath = currentJob.getCaseDirectoryPath();
|
||||||
AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath);
|
AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath);
|
||||||
try {
|
try {
|
||||||
caseForJob.notifyAddingDataSource(taskId);
|
caseForJob.notifyAddingDataSource(taskId);
|
||||||
|
|
||||||
// lookup all AutomatedIngestDataSourceProcessors
|
Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap;
|
||||||
Collection<? extends AutoIngestDataSourceProcessor> processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class);
|
try {
|
||||||
|
// lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source
|
||||||
Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap = new HashMap<>();
|
validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSource.getPath());
|
||||||
for (AutoIngestDataSourceProcessor processor : processorCandidates) {
|
} catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) {
|
||||||
try {
|
SYS_LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", dataSource.getPath());
|
||||||
int confidence = processor.canProcess(dataSource.getPath());
|
// rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause.
|
||||||
if (confidence > 0) {
|
throw ex;
|
||||||
validDataSourceProcessorsMap.put(processor, confidence);
|
|
||||||
}
|
|
||||||
} catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) {
|
|
||||||
SYS_LOGGER.log(Level.SEVERE, "Exception while determining whether data source processor {0} can process {1}", new Object[]{processor.getDataSourceType(), dataSource.getPath()});
|
|
||||||
// rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause.
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// did we find a data source processor that can process the data source
|
// did we find a data source processor that can process the data source
|
||||||
@ -2590,80 +2577,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
jobLogger.logFileExportError();
|
jobLogger.logFileExportError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A "callback" that collects the results of running a data source
|
|
||||||
* processor on a data source and unblocks the job processing thread
|
|
||||||
* when the data source processor finishes running in its own thread.
|
|
||||||
*/
|
|
||||||
@Immutable
|
|
||||||
class AddDataSourceCallback extends DataSourceProcessorCallback {
|
|
||||||
|
|
||||||
private final Case caseForJob;
|
|
||||||
private final DataSource dataSourceInfo;
|
|
||||||
private final UUID taskId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a "callback" that collects the results of running a
|
|
||||||
* data source processor on a data source and unblocks the job
|
|
||||||
* processing thread when the data source processor finishes running
|
|
||||||
* in its own thread.
|
|
||||||
*
|
|
||||||
* @param caseForJob The case for the current job.
|
|
||||||
* @param dataSourceInfo The data source
|
|
||||||
* @param taskId The task id to associate with ingest job
|
|
||||||
* events.
|
|
||||||
*/
|
|
||||||
AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId) {
|
|
||||||
this.caseForJob = caseForJob;
|
|
||||||
this.dataSourceInfo = dataSourceInfo;
|
|
||||||
this.taskId = taskId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the data source processor when it finishes running in
|
|
||||||
* its own thread.
|
|
||||||
*
|
|
||||||
* @param result The result code for the processing of
|
|
||||||
* the data source.
|
|
||||||
* @param errorMessages Any error messages generated during the
|
|
||||||
* processing of the data source.
|
|
||||||
* @param dataSourceContent The content produced by processing the
|
|
||||||
* data source.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSourceContent) {
|
|
||||||
if (!dataSourceContent.isEmpty()) {
|
|
||||||
caseForJob.notifyDataSourceAdded(dataSourceContent.get(0), taskId);
|
|
||||||
} else {
|
|
||||||
caseForJob.notifyFailedAddingDataSource(taskId);
|
|
||||||
}
|
|
||||||
dataSourceInfo.setDataSourceProcessorOutput(result, errorMessages, dataSourceContent);
|
|
||||||
dataSourceContent.addAll(dataSourceContent);
|
|
||||||
synchronized (ingestLock) {
|
|
||||||
ingestLock.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the data source processor when it finishes running in
|
|
||||||
* its own thread, if that thread is the AWT (Abstract Window
|
|
||||||
* Toolkit) event dispatch thread (EDT).
|
|
||||||
*
|
|
||||||
* @param result The result code for the processing of
|
|
||||||
* the data source.
|
|
||||||
* @param errorMessages Any error messages generated during the
|
|
||||||
* processing of the data source.
|
|
||||||
* @param dataSourceContent The content produced by processing the
|
|
||||||
* data source.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSources) {
|
|
||||||
done(result, errorMessages, dataSources);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data source processor progress monitor does nothing. There is
|
* A data source processor progress monitor does nothing. There is
|
||||||
* currently no mechanism for showing or recording data source processor
|
* currently no mechanism for showing or recording data source processor
|
||||||
@ -3003,49 +2917,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
PARTIALLY_DELETED,
|
PARTIALLY_DELETED,
|
||||||
FULLY_DELETED
|
FULLY_DELETED
|
||||||
}
|
}
|
||||||
|
|
||||||
@ThreadSafe
|
|
||||||
private static final class DataSource {
|
|
||||||
|
|
||||||
private final String deviceId;
|
|
||||||
private final Path path;
|
|
||||||
private DataSourceProcessorResult resultCode;
|
|
||||||
private List<String> errorMessages;
|
|
||||||
private List<Content> content;
|
|
||||||
|
|
||||||
DataSource(String deviceId, Path path) {
|
|
||||||
this.deviceId = deviceId;
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getDeviceId() {
|
|
||||||
return deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path getPath() {
|
|
||||||
return this.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List<String> errorMessages, List<Content> content) {
|
|
||||||
this.resultCode = result;
|
|
||||||
this.errorMessages = new ArrayList<>(errorMessages);
|
|
||||||
this.content = new ArrayList<>(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode() {
|
|
||||||
return resultCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized List<String> getDataSourceProcessorErrorMessages() {
|
|
||||||
return new ArrayList<>(errorMessages);
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized List<Content> getContent() {
|
|
||||||
return new ArrayList<>(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class AutoIngestManagerException extends Exception {
|
static final class AutoIngestManagerException extends Exception {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ -247,3 +247,7 @@ AutoIngestDashboard.prioritizeJobButton.toolTipText=Move the selected job to the
|
|||||||
AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job
|
AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job
|
||||||
AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue.
|
AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue.
|
||||||
AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case
|
AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case
|
||||||
|
ArchiveFilePanel.pathLabel.text=Browse for an archive file:
|
||||||
|
ArchiveFilePanel.browseButton.text=Browse
|
||||||
|
ArchiveFilePanel.pathTextField.text=
|
||||||
|
ArchiveFilePanel.errorLabel.text=Error Label
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-2017 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.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
class DataSource {
|
||||||
|
|
||||||
|
private final String deviceId;
|
||||||
|
private final Path path;
|
||||||
|
private DataSourceProcessorResult resultCode;
|
||||||
|
private List<String> errorMessages;
|
||||||
|
private List<Content> content;
|
||||||
|
|
||||||
|
DataSource(String deviceId, Path path) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path getPath() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List<String> errorMessages, List<Content> content) {
|
||||||
|
this.resultCode = result;
|
||||||
|
this.errorMessages = new ArrayList<>(errorMessages);
|
||||||
|
this.content = new ArrayList<>(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode() {
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized List<String> getDataSourceProcessorErrorMessages() {
|
||||||
|
return new ArrayList<>(errorMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized List<Content> getContent() {
|
||||||
|
return new ArrayList<>(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-2017 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.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.openide.util.Lookup;
|
||||||
|
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||||
|
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class to find Data Source Processors
|
||||||
|
*/
|
||||||
|
class DataSourceProcessorUtility {
|
||||||
|
|
||||||
|
private DataSourceProcessorUtility() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility method to find all Data Source Processors (DSP) that are able
|
||||||
|
* to process the input data source. Only the DSPs that implement
|
||||||
|
* AutoIngestDataSourceProcessor interface are used.
|
||||||
|
*
|
||||||
|
* @param dataSourcePath Full path to the data source
|
||||||
|
* @return Hash map of all DSPs that can process the data source along with
|
||||||
|
* their confidence score
|
||||||
|
* @throws
|
||||||
|
* org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException
|
||||||
|
*/
|
||||||
|
static Map<AutoIngestDataSourceProcessor, Integer> getDataSourceProcessor(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
|
||||||
|
|
||||||
|
// lookup all AutomatedIngestDataSourceProcessors
|
||||||
|
Collection<? extends AutoIngestDataSourceProcessor> processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class);
|
||||||
|
|
||||||
|
Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap = new HashMap<>();
|
||||||
|
for (AutoIngestDataSourceProcessor processor : processorCandidates) {
|
||||||
|
int confidence = processor.canProcess(dataSourcePath);
|
||||||
|
if (confidence > 0) {
|
||||||
|
validDataSourceProcessorsMap.put(processor, confidence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validDataSourceProcessorsMap;
|
||||||
|
}
|
||||||
|
}
|
@ -236,9 +236,7 @@ public final class ImageGalleryController {
|
|||||||
undoManager.clear();
|
undoManager.clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
regroupDisabled.addListener((Observable observable) -> {
|
regroupDisabled.addListener(observable -> checkForGroups());
|
||||||
checkForGroups();
|
|
||||||
});
|
|
||||||
|
|
||||||
IngestManager ingestManager = IngestManager.getInstance();
|
IngestManager ingestManager = IngestManager.getInstance();
|
||||||
PropertyChangeListener ingestEventHandler =
|
PropertyChangeListener ingestEventHandler =
|
||||||
|
@ -128,9 +128,7 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
|
|||||||
LOGGER.log(Level.WARNING, "could not access case during getFilesWithHashSetHitsCount()"); //NON-NLS
|
LOGGER.log(Level.WARNING, "could not access case during getFilesWithHashSetHitsCount()"); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hashSetHitsCount.get();
|
return hashSetHitsCount.get();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyLongProperty hashSetHitsCountProperty() {
|
public ReadOnlyLongProperty hashSetHitsCountProperty() {
|
||||||
@ -226,7 +224,6 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
|
|||||||
// By default, sort by group key name
|
// By default, sort by group key name
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(DrawableGroup other) {
|
public int compareTo(DrawableGroup other) {
|
||||||
return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName());
|
return getGroupByValueDislpayName().compareTo(other.getGroupByValueDislpayName());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ public class GroupManager {
|
|||||||
/*
|
/*
|
||||||
* --- current grouping/sorting attributes ---
|
* --- current grouping/sorting attributes ---
|
||||||
*/
|
*/
|
||||||
private volatile GroupSortBy sortBy = GroupSortBy.NONE;
|
private volatile GroupSortBy sortBy = GroupSortBy.PRIORITY;
|
||||||
private volatile DrawableAttribute<?> groupBy = DrawableAttribute.PATH;
|
private volatile DrawableAttribute<?> groupBy = DrawableAttribute.PATH;
|
||||||
private volatile SortOrder sortOrder = SortOrder.ASCENDING;
|
private volatile SortOrder sortOrder = SortOrder.ASCENDING;
|
||||||
|
|
||||||
@ -156,7 +156,6 @@ public class GroupManager {
|
|||||||
*/
|
*/
|
||||||
public GroupManager(ImageGalleryController controller) {
|
public GroupManager(ImageGalleryController controller) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -188,7 +187,7 @@ public class GroupManager {
|
|||||||
* the groups the given file is a part of
|
* the groups the given file is a part of
|
||||||
*
|
*
|
||||||
* @return a a set of {@link GroupKey}s representing the group(s) the given
|
* @return a a set of {@link GroupKey}s representing the group(s) the given
|
||||||
* file is a part of
|
* file is a part of
|
||||||
*/
|
*/
|
||||||
synchronized public Set<GroupKey<?>> getGroupKeysForFileID(Long fileID) {
|
synchronized public Set<GroupKey<?>> getGroupKeysForFileID(Long fileID) {
|
||||||
try {
|
try {
|
||||||
@ -208,7 +207,7 @@ public class GroupManager {
|
|||||||
* @param groupKey
|
* @param groupKey
|
||||||
*
|
*
|
||||||
* @return return the DrawableGroup (if it exists) for the given GroupKey,
|
* @return return the DrawableGroup (if it exists) for the given GroupKey,
|
||||||
* or null if no group exists for that key.
|
* or null if no group exists for that key.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public DrawableGroup getGroupForKey(@Nonnull GroupKey<?> groupKey) {
|
public DrawableGroup getGroupForKey(@Nonnull GroupKey<?> groupKey) {
|
||||||
@ -284,7 +283,7 @@ public class GroupManager {
|
|||||||
* no-op
|
* no-op
|
||||||
*
|
*
|
||||||
* @param groupKey the value of groupKey
|
* @param groupKey the value of groupKey
|
||||||
* @param fileID the value of file
|
* @param fileID the value of file
|
||||||
*/
|
*/
|
||||||
public synchronized DrawableGroup removeFromGroup(GroupKey<?> groupKey, final Long fileID) {
|
public synchronized DrawableGroup removeFromGroup(GroupKey<?> groupKey, final Long fileID) {
|
||||||
//get grouping this file would be in
|
//get grouping this file would be in
|
||||||
@ -466,7 +465,7 @@ public class GroupManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Comparator<DrawableGroup> getSortBy() {
|
public GroupSortBy getSortBy() {
|
||||||
return sortBy;
|
return sortBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,7 +511,7 @@ public class GroupManager {
|
|||||||
* @param groupBy
|
* @param groupBy
|
||||||
* @param sortBy
|
* @param sortBy
|
||||||
* @param sortOrder
|
* @param sortOrder
|
||||||
* @param force true to force a full db query regroup
|
* @param force true to force a full db query regroup
|
||||||
*/
|
*/
|
||||||
public synchronized <A extends Comparable<A>> void regroup(final DrawableAttribute<A> groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) {
|
public synchronized <A extends Comparable<A>> void regroup(final DrawableAttribute<A> groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) {
|
||||||
|
|
||||||
@ -530,9 +529,7 @@ public class GroupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
groupByTask = new ReGroupTask<>(groupBy, sortBy, sortOrder);
|
groupByTask = new ReGroupTask<>(groupBy, sortBy, sortOrder);
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> regroupProgress.bind(groupByTask.progressProperty()));
|
||||||
regroupProgress.bind(groupByTask.progressProperty());
|
|
||||||
});
|
|
||||||
regroupExecutor.submit(groupByTask);
|
regroupExecutor.submit(groupByTask);
|
||||||
} else {
|
} else {
|
||||||
// resort the list of groups
|
// resort the list of groups
|
||||||
@ -583,10 +580,7 @@ public class GroupManager {
|
|||||||
DrawableGroup group = g;
|
DrawableGroup group = g;
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
//if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it.
|
//if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it.
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> group.addFile(fileID));
|
||||||
group.addFile(fileID);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,9 +676,9 @@ public class GroupManager {
|
|||||||
} else {
|
} else {
|
||||||
group = new DrawableGroup(groupKey, fileIDs, groupSeen);
|
group = new DrawableGroup(groupKey, fileIDs, groupSeen);
|
||||||
controller.getCategoryManager().registerListener(group);
|
controller.getCategoryManager().registerListener(group);
|
||||||
group.seenProperty().addListener((o, oldSeen, newSeen) -> {
|
group.seenProperty().addListener((o, oldSeen, newSeen) ->
|
||||||
Platform.runLater(() -> markGroupSeen(group, newSeen));
|
Platform.runLater(() -> markGroupSeen(group, newSeen))
|
||||||
});
|
);
|
||||||
groupMap.put(groupKey, group);
|
groupMap.put(groupKey, group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -693,7 +687,7 @@ public class GroupManager {
|
|||||||
analyzedGroups.add(group);
|
analyzedGroups.add(group);
|
||||||
if (Objects.isNull(task)) {
|
if (Objects.isNull(task)) {
|
||||||
FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
|
FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
markGroupSeen(group, groupSeen);
|
markGroupSeen(group, groupSeen);
|
||||||
});
|
});
|
||||||
@ -743,17 +737,17 @@ public class GroupManager {
|
|||||||
"# {0} - groupBy attribute Name",
|
"# {0} - groupBy attribute Name",
|
||||||
"# {1} - atribute value",
|
"# {1} - atribute value",
|
||||||
"ReGroupTask.progressUpdate=regrouping files by {0} : {1}"})
|
"ReGroupTask.progressUpdate=regrouping files by {0} : {1}"})
|
||||||
private class ReGroupTask<A extends Comparable<A>> extends LoggedTask<Void> {
|
private class ReGroupTask<AttrType extends Comparable<AttrType>> extends LoggedTask<Void> {
|
||||||
|
|
||||||
private ProgressHandle groupProgress;
|
private ProgressHandle groupProgress;
|
||||||
|
|
||||||
private final DrawableAttribute<A> groupBy;
|
private final DrawableAttribute<AttrType> groupBy;
|
||||||
|
|
||||||
private final GroupSortBy sortBy;
|
private final GroupSortBy sortBy;
|
||||||
|
|
||||||
private final SortOrder sortOrder;
|
private final SortOrder sortOrder;
|
||||||
|
|
||||||
ReGroupTask(DrawableAttribute<A> groupBy, GroupSortBy sortBy, SortOrder sortOrder) {
|
ReGroupTask(DrawableAttribute<AttrType> groupBy, GroupSortBy sortBy, SortOrder sortOrder) {
|
||||||
super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), true);
|
super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), true);
|
||||||
|
|
||||||
this.groupBy = groupBy;
|
this.groupBy = groupBy;
|
||||||
@ -780,13 +774,13 @@ public class GroupManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Get the list of group keys
|
// Get the list of group keys
|
||||||
final List<A> vals = findValuesForAttribute(groupBy);
|
final List<AttrType> vals = findValuesForAttribute(groupBy);
|
||||||
|
|
||||||
groupProgress.start(vals.size());
|
groupProgress.start(vals.size());
|
||||||
|
|
||||||
int p = 0;
|
int p = 0;
|
||||||
// For each key value, partially create the group and add it to the list.
|
// For each key value, partially create the group and add it to the list.
|
||||||
for (final A val : vals) {
|
for (final AttrType val : vals) {
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
return null;//abort
|
return null;//abort
|
||||||
}
|
}
|
||||||
|
@ -37,24 +37,34 @@ public class GroupSortBy implements Comparator<DrawableGroup> {
|
|||||||
/**
|
/**
|
||||||
* sort the groups by the number of files in each
|
* sort the groups by the number of files in each
|
||||||
*/
|
*/
|
||||||
public final static GroupSortBy FILE_COUNT = new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png", Comparator.comparing(DrawableGroup::getSize));
|
public final static GroupSortBy FILE_COUNT =
|
||||||
|
new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png",
|
||||||
|
Comparator.comparing(DrawableGroup::getSize));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sort the groups by the natural order of the grouping value ( eg group
|
* sort the groups by the natural order of the grouping value ( eg group
|
||||||
* them by path alphabetically )
|
* them by path alphabetically )
|
||||||
*/
|
*/
|
||||||
public final static GroupSortBy GROUP_BY_VALUE = new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png", Comparator.comparing(DrawableGroup::getGroupByValueDislpayName));
|
public final static GroupSortBy GROUP_BY_VALUE =
|
||||||
|
new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png",
|
||||||
|
Comparator.comparing(DrawableGroup::getGroupByValueDislpayName));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* don't sort the groups just use what ever order they come in (ingest
|
* don't sort the groups just use what ever order they come in (ingest
|
||||||
* order)
|
* order)
|
||||||
*/
|
*/
|
||||||
public final static GroupSortBy NONE = new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png", new AllEqualComparator<>());
|
public final static GroupSortBy NONE =
|
||||||
|
new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png",
|
||||||
|
new AllEqualComparator<>());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sort the groups by some priority metric to be determined and implemented
|
* sort the groups by some priority metric to be determined and implemented
|
||||||
*/
|
*/
|
||||||
public final static GroupSortBy PRIORITY = new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", Comparator.comparing(DrawableGroup::getHashHitDensity).thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)).reversed());
|
public final static GroupSortBy PRIORITY =
|
||||||
|
new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png",
|
||||||
|
Comparator.comparing(DrawableGroup::getHashHitDensity)
|
||||||
|
.thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount))
|
||||||
|
.reversed());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(DrawableGroup o1, DrawableGroup o2) {
|
public int compare(DrawableGroup o1, DrawableGroup o2) {
|
||||||
|
@ -180,8 +180,8 @@ public class Toolbar extends ToolBar {
|
|||||||
|
|
||||||
sortChooser = new SortChooser<>(GroupSortBy.getValues());
|
sortChooser = new SortChooser<>(GroupSortBy.getValues());
|
||||||
sortChooser.comparatorProperty().addListener((observable, oldComparator, newComparator) -> {
|
sortChooser.comparatorProperty().addListener((observable, oldComparator, newComparator) -> {
|
||||||
final boolean orderEnabled = newComparator == GroupSortBy.NONE || newComparator == GroupSortBy.PRIORITY;
|
final boolean orderDisabled = newComparator == GroupSortBy.NONE || newComparator == GroupSortBy.PRIORITY;
|
||||||
sortChooser.setSortOrderDisabled(orderEnabled);
|
sortChooser.setSortOrderDisabled(orderDisabled);
|
||||||
|
|
||||||
final SortChooser.ValueType valueType = newComparator == GroupSortBy.GROUP_BY_VALUE ? SortChooser.ValueType.LEXICOGRAPHIC : SortChooser.ValueType.NUMERIC;
|
final SortChooser.ValueType valueType = newComparator == GroupSortBy.GROUP_BY_VALUE ? SortChooser.ValueType.LEXICOGRAPHIC : SortChooser.ValueType.NUMERIC;
|
||||||
sortChooser.setValueType(valueType);
|
sortChooser.setValueType(valueType);
|
||||||
@ -189,7 +189,7 @@ public class Toolbar extends ToolBar {
|
|||||||
});
|
});
|
||||||
|
|
||||||
sortChooser.sortOrderProperty().addListener(queryInvalidationListener);
|
sortChooser.sortOrderProperty().addListener(queryInvalidationListener);
|
||||||
sortChooser.setComparator(GroupSortBy.PRIORITY);
|
sortChooser.setComparator(controller.getGroupManager().getSortBy());
|
||||||
getItems().add(1, sortChooser);
|
getItems().add(1, sortChooser);
|
||||||
sortHelpImageView.setCursor(Cursor.HAND);
|
sortHelpImageView.setCursor(Cursor.HAND);
|
||||||
|
|
||||||
|
@ -6,8 +6,21 @@
|
|||||||
<description>Builds, tests, and runs the project org.sleuthkit.autopsy.keywordsearch.</description>
|
<description>Builds, tests, and runs the project org.sleuthkit.autopsy.keywordsearch.</description>
|
||||||
<import file="nbproject/build-impl.xml"/>
|
<import file="nbproject/build-impl.xml"/>
|
||||||
<import file="../BootstrapIvy.xml"/>
|
<import file="../BootstrapIvy.xml"/>
|
||||||
|
<property name="lib" location="release/modules/ext"/>
|
||||||
|
<property name="autopsy-lib" location="../CoreLibs/release/modules/ext"/>
|
||||||
|
<property name="build" location="build/classes"/>
|
||||||
|
<property name="build-test" location="build/test/unit/classes"/>
|
||||||
|
|
||||||
|
<path id="libs">
|
||||||
|
<fileset dir="${lib}">
|
||||||
|
<include name="*.jar"/>
|
||||||
|
</fileset>
|
||||||
|
<fileset dir="${autopsy-lib}">
|
||||||
|
<include name="*.jar"/>
|
||||||
|
</fileset>
|
||||||
|
<pathelement path="${build}"/>
|
||||||
|
<pathelement path="${build-test}"/>
|
||||||
|
</path>
|
||||||
<target name="get-solr-deployment" description="copy the solr deployment into release">
|
<target name="get-solr-deployment" description="copy the solr deployment into release">
|
||||||
<copy todir="${basedir}/release/solr" >
|
<copy todir="${basedir}/release/solr" >
|
||||||
<fileset dir="solr"/>
|
<fileset dir="solr"/>
|
||||||
@ -39,5 +52,12 @@
|
|||||||
<target name="clean-all" depends="clean" description="Clear Ivy cache.">
|
<target name="clean-all" depends="clean" description="Clear Ivy cache.">
|
||||||
<ivy:cleancache/>
|
<ivy:cleancache/>
|
||||||
</target>
|
</target>
|
||||||
|
<target name="test-unit" depends="init, test-init, test-build">
|
||||||
|
<junit fork="on" haltonfailure="yes" dir=".">
|
||||||
|
<formatter type="plain" usefile="false" />
|
||||||
|
<classpath refid="libs"/>
|
||||||
|
<test name="org.sleuthkit.autopsy.keywordsearch.KeywordSearchTestSuite" />
|
||||||
|
</junit>
|
||||||
|
</target>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -138,12 +138,14 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPropertyChangeListener(PropertyChangeListener l) {
|
public void addPropertyChangeListener(PropertyChangeListener l) {
|
||||||
|
super.addPropertyChangeListener(l);
|
||||||
listsManagementPanel.addPropertyChangeListener(l);
|
listsManagementPanel.addPropertyChangeListener(l);
|
||||||
editListPanel.addPropertyChangeListener(l);
|
editListPanel.addPropertyChangeListener(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removePropertyChangeListener(PropertyChangeListener l) {
|
public void removePropertyChangeListener(PropertyChangeListener l) {
|
||||||
|
super.removePropertyChangeListener(l);
|
||||||
listsManagementPanel.removePropertyChangeListener(l);
|
listsManagementPanel.removePropertyChangeListener(l);
|
||||||
editListPanel.removePropertyChangeListener(l);
|
editListPanel.removePropertyChangeListener(l);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2016 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -28,11 +28,12 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
|||||||
*/
|
*/
|
||||||
final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
|
final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
|
||||||
|
|
||||||
private GlobalListSettingsPanel listsPanel;
|
private static final long serialVersionUID = 1L;
|
||||||
private KeywordSearchGlobalLanguageSettingsPanel languagesPanel;
|
private final GlobalListSettingsPanel listsPanel = new GlobalListSettingsPanel();
|
||||||
private KeywordSearchGlobalSearchSettingsPanel generalPanel;
|
private final KeywordSearchGlobalLanguageSettingsPanel languagesPanel = new KeywordSearchGlobalLanguageSettingsPanel();
|
||||||
|
private final KeywordSearchGlobalSearchSettingsPanel generalPanel = new KeywordSearchGlobalSearchSettingsPanel();
|
||||||
|
|
||||||
public KeywordSearchGlobalSettingsPanel() {
|
KeywordSearchGlobalSettingsPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
customizeComponents();
|
customizeComponents();
|
||||||
}
|
}
|
||||||
@ -40,9 +41,6 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP
|
|||||||
@NbBundle.Messages({"KeywordSearchGlobalSettingsPanel.Title=Global Keyword Search Settings"})
|
@NbBundle.Messages({"KeywordSearchGlobalSettingsPanel.Title=Global Keyword Search Settings"})
|
||||||
private void customizeComponents() {
|
private void customizeComponents() {
|
||||||
setName(Bundle.KeywordSearchGlobalSettingsPanel_Title());
|
setName(Bundle.KeywordSearchGlobalSettingsPanel_Title());
|
||||||
listsPanel = new GlobalListSettingsPanel();
|
|
||||||
languagesPanel = new KeywordSearchGlobalLanguageSettingsPanel();
|
|
||||||
generalPanel = new KeywordSearchGlobalSearchSettingsPanel();
|
|
||||||
tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listTabTitle"), null,
|
tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listTabTitle"), null,
|
||||||
listsPanel, NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listLabToolTip"), 0);
|
listsPanel, NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listLabToolTip"), 0);
|
||||||
tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.stringExtTitle"), null,
|
tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.stringExtTitle"), null,
|
||||||
@ -53,6 +51,7 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addPropertyChangeListener(PropertyChangeListener l) {
|
public void addPropertyChangeListener(PropertyChangeListener l) {
|
||||||
|
super.addPropertyChangeListener(l);
|
||||||
listsPanel.addPropertyChangeListener(l);
|
listsPanel.addPropertyChangeListener(l);
|
||||||
languagesPanel.addPropertyChangeListener(l);
|
languagesPanel.addPropertyChangeListener(l);
|
||||||
generalPanel.addPropertyChangeListener(l);
|
generalPanel.addPropertyChangeListener(l);
|
||||||
@ -60,6 +59,7 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removePropertyChangeListener(PropertyChangeListener l) {
|
public void removePropertyChangeListener(PropertyChangeListener l) {
|
||||||
|
super.removePropertyChangeListener(l);
|
||||||
listsPanel.removePropertyChangeListener(l);
|
listsPanel.removePropertyChangeListener(l);
|
||||||
languagesPanel.removePropertyChangeListener(l);
|
languagesPanel.removePropertyChangeListener(l);
|
||||||
generalPanel.removePropertyChangeListener(l);
|
generalPanel.removePropertyChangeListener(l);
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-2017 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.keywordsearch;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Suite;
|
||||||
|
|
||||||
|
@RunWith(Suite.class)
|
||||||
|
@Suite.SuiteClasses({CreditCardValidatorTest.class})
|
||||||
|
public class KeywordSearchTestSuite {
|
||||||
|
public KeywordSearchTestSuite() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpClass() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownClass() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
public static void main(String[] args) {
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user