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 {
|
||||
|
||||
final private T component;
|
||||
|
||||
private String lastErrorMessage;
|
||||
|
||||
AbstractFileSearchFilter(T component) {
|
||||
this.component = component;
|
||||
this.lastErrorMessage = "";
|
||||
}
|
||||
|
||||
void setLastError(String mes){
|
||||
lastErrorMessage = mes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLastError(){
|
||||
return this.lastErrorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,4 +57,5 @@ MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected
|
||||
FileSearchPanel.searchButton.text=Search
|
||||
MimeTypePanel.mimeTypeCheckBox.text=MIME Type:
|
||||
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 org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
|
||||
/**
|
||||
* Filters file date properties (modified/created/etc.. times)
|
||||
@ -79,25 +80,10 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
|
||||
String query = "NULL";
|
||||
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
|
||||
long fromDate = 0;
|
||||
String startDateValue = panel.getDateFromTextField().getText();
|
||||
Calendar startDate = null;
|
||||
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
|
||||
}
|
||||
Calendar startDate = getCalendarDate(startDateValue);
|
||||
if (!startDateValue.isEmpty()) {
|
||||
if (startDate != null) {
|
||||
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;
|
||||
String endDateValue = panel.getDateToTextField().getText();
|
||||
Calendar endDate = null;
|
||||
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
|
||||
}
|
||||
Calendar endDate = getCalendarDate(endDateValue);
|
||||
if (!endDateValue.isEmpty()) {
|
||||
if (endDate != null) {
|
||||
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 changedChecked = panel.getChangedCheckBox().isSelected();
|
||||
final boolean accessedChecked = panel.getAccessedCheckBox().isSelected();
|
||||
@ -206,14 +174,56 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
|
||||
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
|
||||
public void addActionListener(ActionListener l) {
|
||||
getComponent().addActionListener(l);
|
||||
}
|
||||
|
||||
@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() {
|
||||
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>
|
||||
<Component class="javax.swing.JFormattedTextField" name="dateToTextField">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<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}")"/>
|
||||
</Property>
|
||||
@ -208,6 +209,7 @@
|
||||
</Component>
|
||||
<Component class="javax.swing.JFormattedTextField" name="dateFromTextField">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<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}")"/>
|
||||
</Property>
|
||||
|
@ -29,6 +29,8 @@ import javax.swing.JComboBox;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
/**
|
||||
* Subpanel with controls for file data filtering.
|
||||
@ -50,6 +52,7 @@ class DateSearchPanel extends javax.swing.JPanel {
|
||||
|
||||
dateFromTextField.setComponentPopupMenu(rightClickMenu);
|
||||
dateToTextField.setComponentPopupMenu(rightClickMenu);
|
||||
|
||||
ActionListener actList = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
@ -74,6 +77,41 @@ class DateSearchPanel extends javax.swing.JPanel {
|
||||
copyMenuItem.addActionListener(actList);
|
||||
pasteMenuItem.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();
|
||||
}
|
||||
|
||||
@ -176,6 +214,7 @@ class DateSearchPanel extends javax.swing.JPanel {
|
||||
selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.selectAllMenuItem.text")); // NOI18N
|
||||
rightClickMenu.add(selectAllMenuItem);
|
||||
|
||||
dateToTextField.setEditable(false);
|
||||
dateToTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateToTextField.text")); // NOI18N
|
||||
dateToTextField.addFocusListener(new java.awt.event.FocusAdapter() {
|
||||
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.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.addFocusListener(new java.awt.event.FocusAdapter() {
|
||||
public void focusLost(java.awt.event.FocusEvent evt) {
|
||||
@ -365,6 +405,7 @@ class DateSearchPanel extends javax.swing.JPanel {
|
||||
if (evt.getNewValue() instanceof Date) {
|
||||
setToDate((Date) evt.getNewValue());
|
||||
}
|
||||
|
||||
}//GEN-LAST:event_dateToPopupChanged
|
||||
|
||||
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) {
|
||||
dateStringResult = dateFormat.format(date);
|
||||
}
|
||||
|
||||
dateFromTextField.setText(dateStringResult);
|
||||
dateFromButtonCalendar.setTargetDate(date);
|
||||
}
|
||||
|
@ -47,6 +47,13 @@ interface FileSearchFilter {
|
||||
* @return Whether the panel has valid input for search.
|
||||
*/
|
||||
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
|
||||
|
@ -23,7 +23,9 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="filterPanel" alignment="0" max="32767" 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"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@ -32,9 +34,14 @@
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="filterPanel" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="filterPanel" pref="266" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" 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"/>
|
||||
</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}")"/>
|
||||
</Property>
|
||||
</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>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -27,7 +27,6 @@ package org.sleuthkit.autopsy.filesearch;
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
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());
|
||||
}
|
||||
|
||||
@ -130,11 +123,13 @@ class FileSearchPanel extends javax.swing.JPanel {
|
||||
if (filter.isEnabled()) {
|
||||
enabled = true;
|
||||
if (!filter.isValid()) {
|
||||
errorLabel.setText(filter.getLastError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorLabel.setText("");
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@ -280,6 +275,7 @@ class FileSearchPanel extends javax.swing.JPanel {
|
||||
|
||||
filterPanel = new javax.swing.JPanel();
|
||||
searchButton = new javax.swing.JButton();
|
||||
errorLabel = new javax.swing.JLabel();
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
this.setLayout(layout);
|
||||
@ -295,21 +299,31 @@ class FileSearchPanel extends javax.swing.JPanel {
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.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)
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(searchButton)
|
||||
.addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(searchButton)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(errorLabel)))
|
||||
.addContainerGap())
|
||||
);
|
||||
}// </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
|
||||
private javax.swing.JLabel errorLabel;
|
||||
private javax.swing.JPanel filterPanel;
|
||||
private javax.swing.JButton searchButton;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.filesearch;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||
|
||||
/**
|
||||
@ -60,7 +61,25 @@ class HashSearchFilter extends AbstractFileSearchFilter<HashSearchPanel> {
|
||||
}
|
||||
|
||||
@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() {
|
||||
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 org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.datamodel.TskData.FileKnown;
|
||||
|
||||
/**
|
||||
@ -85,7 +86,14 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter<KnownStatusSearch
|
||||
}
|
||||
|
||||
@Override
|
||||
@Messages ({
|
||||
"KnownStatusSearchFilter.errorMessage.noKnownStatusCheckboxSelected=At least one known status checkbox must be selected."
|
||||
})
|
||||
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;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
|
||||
/**
|
||||
* Filter by mime type used in filter areas of file search by attribute.
|
||||
@ -42,7 +43,14 @@ class MimeTypeFilter extends AbstractFileSearchFilter<MimeTypePanel> {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Messages ({
|
||||
"MimeTypeFilter.errorMessage.emptyMimeType=At least one MIME type must be selected."
|
||||
})
|
||||
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 org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||
|
||||
/**
|
||||
@ -64,7 +65,14 @@ class NameSearchFilter extends AbstractFileSearchFilter<NameSearchPanel> {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Messages ({
|
||||
"NameSearchFilter.errorMessage.emtpyName=Please input a name to search."
|
||||
})
|
||||
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 javax.swing.JComboBox;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||
|
||||
/**
|
||||
@ -74,7 +75,23 @@ class SizeSearchFilter extends AbstractFileSearchFilter<SizeSearchPanel> {
|
||||
}
|
||||
|
||||
@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() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFormattedTextField;
|
||||
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);
|
||||
pasteMenuItem.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();
|
||||
logDiskSpaceUsage();
|
||||
|
||||
if (!enoughDiskSpace()) {
|
||||
/*
|
||||
* Shut down ingest by cancelling all ingest jobs.
|
||||
|
@ -33,7 +33,8 @@ import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile;
|
||||
*/
|
||||
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.newProfileText=NewEmptyProfile",
|
||||
"ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named.",
|
||||
@ -50,6 +51,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel {
|
||||
*/
|
||||
ProfilePanel() {
|
||||
initComponents();
|
||||
setName(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.title.text"));
|
||||
settings = new IngestJobSettings(NEW_PROFILE_NAME);
|
||||
ingestSettingsPanel = new IngestJobSettingsPanel(settings);
|
||||
ingestSettingsPanel.setPastJobsButtonVisible(false);
|
||||
@ -59,6 +61,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel {
|
||||
|
||||
ProfilePanel(IngestProfile selectedProfile) {
|
||||
initComponents();
|
||||
setName(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.title.text"));
|
||||
profile = selectedProfile;
|
||||
profileDescArea.setText(profile.getDescription());
|
||||
profileNameField.setText(profile.getName());
|
||||
|
@ -4,8 +4,6 @@ OpenIDE-Module-Short-Description=Interesting Files Identifier ingest module.
|
||||
OpenIDE-Module-Name=Interesting Files Identifier
|
||||
OptionsCategory_Name_InterestingItemDefinitions=Interesting Files
|
||||
OptionsCategory_Keywords_InterestingItemDefinitions=InterestingItemDefinitions
|
||||
OptionsCategory_Name_FileIngestFilterDefinitions=File Ingest Filter
|
||||
OptionsCategory_Keywords_FileIngestFilterDefinitions=FileIngestFilterDefinitions
|
||||
InterestingItemsIdentifierIngestModule.moduleName=Interesting Files Identifier
|
||||
InterestingItemsIdentifierIngestModule.moduleDescription=Identifies interesting items as defined by interesting item rule sets.
|
||||
FilesSetPanel.interesting.title=Interesting Files Set
|
||||
@ -45,7 +43,7 @@ FilesSetRulePanel.fileSizeCheck.text=File Size:
|
||||
FilesSetRulePanel.filesRadioButton.text=Files
|
||||
FilesSetRulePanel.dirsRadioButton.text=Directories
|
||||
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.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
|
||||
|
@ -77,6 +77,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
private final JButton okButton = new JButton("OK");
|
||||
private final JButton cancelButton = new JButton("Cancel");
|
||||
private final PANEL_TYPE panelType;
|
||||
private final String filterDialogTitle;
|
||||
private final String ruleDialogTitle;
|
||||
private boolean canBeEnabled = true;
|
||||
|
||||
@ -109,7 +110,8 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
this.jLabel7.setVisible(false);
|
||||
this.fileSizeUnitComboBox.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.equalitySignComboBox.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(jLabel6, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingest.jLabel6.text")); // NOI18N
|
||||
} else {
|
||||
this.filterDialogTitle = "FilesSetPanel.interesting.title";
|
||||
this.ruleDialogTitle = "FilesSetPanel.interesting.title";
|
||||
this.ingoreUnallocCheckbox.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@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() {
|
||||
if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) {
|
||||
setName(Bundle.FilesSetDefsPanel_Ingest_Title());
|
||||
@ -408,7 +411,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
|
||||
// feedback when isValidDefinition() is called.
|
||||
int option = JOptionPane.OK_OPTION;
|
||||
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 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
|
||||
*
|
||||
* Copyright 2014-2016 Basis Technology Corp.
|
||||
* Copyright 2014-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* 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 {
|
||||
|
||||
@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 final String mustBeNamedErrorText;
|
||||
|
@ -44,6 +44,7 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@ -174,7 +175,14 @@ class TableReportGenerator {
|
||||
* does not require a artifact name, so we make a synthetic
|
||||
* 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);
|
||||
}
|
||||
} else {
|
||||
|
@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager;
|
||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -94,9 +93,11 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel {
|
||||
public void mousePressed(MouseEvent evt) {
|
||||
JList<?> list = (JList) evt.getSource();
|
||||
int index = list.locationToIndex(evt.getPoint());
|
||||
String value = tagsNamesListModel.getElementAt(index);
|
||||
tagNameSelections.put(value, !tagNameSelections.get(value));
|
||||
list.repaint();
|
||||
if (index > -1) {
|
||||
String value = tagsNamesListModel.getElementAt(index);
|
||||
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.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import net.sf.sevenzipjbinding.ISequentialOutStream;
|
||||
import net.sf.sevenzipjbinding.ISevenZipInArchive;
|
||||
import net.sf.sevenzipjbinding.SevenZip;
|
||||
@ -35,18 +37,46 @@ import net.sf.sevenzipjbinding.SevenZipNativeInitializationException;
|
||||
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
|
||||
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
|
||||
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.
|
||||
*/
|
||||
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() {
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
@ -37,7 +37,6 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
@ -59,9 +58,6 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
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.sleuthkit.autopsy.casemodule.Case;
|
||||
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.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleError;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* 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 static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest";
|
||||
private final Object ingestLock;
|
||||
private final Object pauseLock;
|
||||
@GuardedBy("pauseLock")
|
||||
@ -2217,7 +2211,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
||||
return;
|
||||
}
|
||||
|
||||
DataSource dataSource = identifyDataSource(caseForJob);
|
||||
DataSource dataSource = identifyDataSource();
|
||||
if (null == dataSource) {
|
||||
currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now()));
|
||||
return;
|
||||
@ -2270,7 +2264,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
||||
* interrupted while blocked, i.e.,
|
||||
* 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();
|
||||
Path manifestPath = manifest.getFilePath();
|
||||
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();
|
||||
return new DataSource(deviceId, dataSourcePath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Passes the data source for the current job through a data source
|
||||
* 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);
|
||||
currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now()));
|
||||
UUID taskId = UUID.randomUUID();
|
||||
DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId);
|
||||
DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock);
|
||||
DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor();
|
||||
Path caseDirectoryPath = currentJob.getCaseDirectoryPath();
|
||||
AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath);
|
||||
try {
|
||||
caseForJob.notifyAddingDataSource(taskId);
|
||||
|
||||
// lookup all AutomatedIngestDataSourceProcessors
|
||||
Collection<? extends AutoIngestDataSourceProcessor> processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class);
|
||||
|
||||
Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap = new HashMap<>();
|
||||
for (AutoIngestDataSourceProcessor processor : processorCandidates) {
|
||||
try {
|
||||
int confidence = processor.canProcess(dataSource.getPath());
|
||||
if (confidence > 0) {
|
||||
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;
|
||||
}
|
||||
Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap;
|
||||
try {
|
||||
// lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source
|
||||
validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSource.getPath());
|
||||
} catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) {
|
||||
SYS_LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", 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
|
||||
@ -2590,80 +2577,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
||||
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
|
||||
* currently no mechanism for showing or recording data source processor
|
||||
@ -3003,49 +2917,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
||||
PARTIALLY_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 {
|
||||
|
||||
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.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue.
|
||||
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();
|
||||
});
|
||||
|
||||
regroupDisabled.addListener((Observable observable) -> {
|
||||
checkForGroups();
|
||||
});
|
||||
regroupDisabled.addListener(observable -> checkForGroups());
|
||||
|
||||
IngestManager ingestManager = IngestManager.getInstance();
|
||||
PropertyChangeListener ingestEventHandler =
|
||||
|
@ -128,9 +128,7 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
|
||||
LOGGER.log(Level.WARNING, "could not access case during getFilesWithHashSetHitsCount()"); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
return hashSetHitsCount.get();
|
||||
|
||||
}
|
||||
|
||||
public ReadOnlyLongProperty hashSetHitsCountProperty() {
|
||||
@ -226,7 +224,6 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
|
||||
// By default, sort by group key name
|
||||
@Override
|
||||
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 ---
|
||||
*/
|
||||
private volatile GroupSortBy sortBy = GroupSortBy.NONE;
|
||||
private volatile GroupSortBy sortBy = GroupSortBy.PRIORITY;
|
||||
private volatile DrawableAttribute<?> groupBy = DrawableAttribute.PATH;
|
||||
private volatile SortOrder sortOrder = SortOrder.ASCENDING;
|
||||
|
||||
@ -156,7 +156,6 @@ public class GroupManager {
|
||||
*/
|
||||
public GroupManager(ImageGalleryController controller) {
|
||||
this.controller = controller;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,7 +187,7 @@ public class GroupManager {
|
||||
* the groups the given file is a part of
|
||||
*
|
||||
* @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) {
|
||||
try {
|
||||
@ -208,7 +207,7 @@ public class GroupManager {
|
||||
* @param 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
|
||||
public DrawableGroup getGroupForKey(@Nonnull GroupKey<?> groupKey) {
|
||||
@ -284,7 +283,7 @@ public class GroupManager {
|
||||
* no-op
|
||||
*
|
||||
* @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) {
|
||||
//get grouping this file would be in
|
||||
@ -466,7 +465,7 @@ public class GroupManager {
|
||||
}
|
||||
}
|
||||
|
||||
public Comparator<DrawableGroup> getSortBy() {
|
||||
public GroupSortBy getSortBy() {
|
||||
return sortBy;
|
||||
}
|
||||
|
||||
@ -512,7 +511,7 @@ public class GroupManager {
|
||||
* @param groupBy
|
||||
* @param sortBy
|
||||
* @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) {
|
||||
|
||||
@ -530,9 +529,7 @@ public class GroupManager {
|
||||
}
|
||||
|
||||
groupByTask = new ReGroupTask<>(groupBy, sortBy, sortOrder);
|
||||
Platform.runLater(() -> {
|
||||
regroupProgress.bind(groupByTask.progressProperty());
|
||||
});
|
||||
Platform.runLater(() -> regroupProgress.bind(groupByTask.progressProperty()));
|
||||
regroupExecutor.submit(groupByTask);
|
||||
} else {
|
||||
// resort the list of groups
|
||||
@ -583,10 +580,7 @@ public class GroupManager {
|
||||
DrawableGroup group = g;
|
||||
if (group != null) {
|
||||
//if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it.
|
||||
Platform.runLater(() -> {
|
||||
group.addFile(fileID);
|
||||
});
|
||||
|
||||
Platform.runLater(() -> group.addFile(fileID));
|
||||
}
|
||||
}
|
||||
|
||||
@ -682,9 +676,9 @@ public class GroupManager {
|
||||
} else {
|
||||
group = new DrawableGroup(groupKey, fileIDs, groupSeen);
|
||||
controller.getCategoryManager().registerListener(group);
|
||||
group.seenProperty().addListener((o, oldSeen, newSeen) -> {
|
||||
Platform.runLater(() -> markGroupSeen(group, newSeen));
|
||||
});
|
||||
group.seenProperty().addListener((o, oldSeen, newSeen) ->
|
||||
Platform.runLater(() -> markGroupSeen(group, newSeen))
|
||||
);
|
||||
groupMap.put(groupKey, group);
|
||||
}
|
||||
}
|
||||
@ -693,7 +687,7 @@ public class GroupManager {
|
||||
analyzedGroups.add(group);
|
||||
if (Objects.isNull(task)) {
|
||||
FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
|
||||
}
|
||||
}
|
||||
}
|
||||
markGroupSeen(group, groupSeen);
|
||||
});
|
||||
@ -743,17 +737,17 @@ public class GroupManager {
|
||||
"# {0} - groupBy attribute Name",
|
||||
"# {1} - atribute value",
|
||||
"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 final DrawableAttribute<A> groupBy;
|
||||
private final DrawableAttribute<AttrType> groupBy;
|
||||
|
||||
private final GroupSortBy sortBy;
|
||||
|
||||
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);
|
||||
|
||||
this.groupBy = groupBy;
|
||||
@ -780,13 +774,13 @@ public class GroupManager {
|
||||
});
|
||||
|
||||
// Get the list of group keys
|
||||
final List<A> vals = findValuesForAttribute(groupBy);
|
||||
final List<AttrType> vals = findValuesForAttribute(groupBy);
|
||||
|
||||
groupProgress.start(vals.size());
|
||||
|
||||
int p = 0;
|
||||
// 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()) {
|
||||
return null;//abort
|
||||
}
|
||||
|
@ -37,24 +37,34 @@ public class GroupSortBy implements Comparator<DrawableGroup> {
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
public int compare(DrawableGroup o1, DrawableGroup o2) {
|
||||
|
@ -180,8 +180,8 @@ public class Toolbar extends ToolBar {
|
||||
|
||||
sortChooser = new SortChooser<>(GroupSortBy.getValues());
|
||||
sortChooser.comparatorProperty().addListener((observable, oldComparator, newComparator) -> {
|
||||
final boolean orderEnabled = newComparator == GroupSortBy.NONE || newComparator == GroupSortBy.PRIORITY;
|
||||
sortChooser.setSortOrderDisabled(orderEnabled);
|
||||
final boolean orderDisabled = newComparator == GroupSortBy.NONE || newComparator == GroupSortBy.PRIORITY;
|
||||
sortChooser.setSortOrderDisabled(orderDisabled);
|
||||
|
||||
final SortChooser.ValueType valueType = newComparator == GroupSortBy.GROUP_BY_VALUE ? SortChooser.ValueType.LEXICOGRAPHIC : SortChooser.ValueType.NUMERIC;
|
||||
sortChooser.setValueType(valueType);
|
||||
@ -189,7 +189,7 @@ public class Toolbar extends ToolBar {
|
||||
});
|
||||
|
||||
sortChooser.sortOrderProperty().addListener(queryInvalidationListener);
|
||||
sortChooser.setComparator(GroupSortBy.PRIORITY);
|
||||
sortChooser.setComparator(controller.getGroupManager().getSortBy());
|
||||
getItems().add(1, sortChooser);
|
||||
sortHelpImageView.setCursor(Cursor.HAND);
|
||||
|
||||
|
@ -6,8 +6,21 @@
|
||||
<description>Builds, tests, and runs the project org.sleuthkit.autopsy.keywordsearch.</description>
|
||||
<import file="nbproject/build-impl.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">
|
||||
<copy todir="${basedir}/release/solr" >
|
||||
<fileset dir="solr"/>
|
||||
@ -39,5 +52,12 @@
|
||||
<target name="clean-all" depends="clean" description="Clear Ivy cache.">
|
||||
<ivy:cleancache/>
|
||||
</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>
|
||||
|
@ -138,12 +138,14 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
|
||||
|
||||
@Override
|
||||
public void addPropertyChangeListener(PropertyChangeListener l) {
|
||||
super.addPropertyChangeListener(l);
|
||||
listsManagementPanel.addPropertyChangeListener(l);
|
||||
editListPanel.addPropertyChangeListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePropertyChangeListener(PropertyChangeListener l) {
|
||||
super.removePropertyChangeListener(l);
|
||||
listsManagementPanel.removePropertyChangeListener(l);
|
||||
editListPanel.removePropertyChangeListener(l);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* 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 {
|
||||
|
||||
private GlobalListSettingsPanel listsPanel;
|
||||
private KeywordSearchGlobalLanguageSettingsPanel languagesPanel;
|
||||
private KeywordSearchGlobalSearchSettingsPanel generalPanel;
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final GlobalListSettingsPanel listsPanel = new GlobalListSettingsPanel();
|
||||
private final KeywordSearchGlobalLanguageSettingsPanel languagesPanel = new KeywordSearchGlobalLanguageSettingsPanel();
|
||||
private final KeywordSearchGlobalSearchSettingsPanel generalPanel = new KeywordSearchGlobalSearchSettingsPanel();
|
||||
|
||||
public KeywordSearchGlobalSettingsPanel() {
|
||||
KeywordSearchGlobalSettingsPanel() {
|
||||
initComponents();
|
||||
customizeComponents();
|
||||
}
|
||||
@ -40,9 +41,6 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP
|
||||
@NbBundle.Messages({"KeywordSearchGlobalSettingsPanel.Title=Global Keyword Search Settings"})
|
||||
private void customizeComponents() {
|
||||
setName(Bundle.KeywordSearchGlobalSettingsPanel_Title());
|
||||
listsPanel = new GlobalListSettingsPanel();
|
||||
languagesPanel = new KeywordSearchGlobalLanguageSettingsPanel();
|
||||
generalPanel = new KeywordSearchGlobalSearchSettingsPanel();
|
||||
tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listTabTitle"), null,
|
||||
listsPanel, NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listLabToolTip"), 0);
|
||||
tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.stringExtTitle"), null,
|
||||
@ -53,6 +51,7 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP
|
||||
|
||||
@Override
|
||||
public void addPropertyChangeListener(PropertyChangeListener l) {
|
||||
super.addPropertyChangeListener(l);
|
||||
listsPanel.addPropertyChangeListener(l);
|
||||
languagesPanel.addPropertyChangeListener(l);
|
||||
generalPanel.addPropertyChangeListener(l);
|
||||
@ -60,6 +59,7 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP
|
||||
|
||||
@Override
|
||||
public void removePropertyChangeListener(PropertyChangeListener l) {
|
||||
super.removePropertyChangeListener(l);
|
||||
listsPanel.removePropertyChangeListener(l);
|
||||
languagesPanel.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