Resolve merge conflict between columns reordering and tag column color

This commit is contained in:
Sophie Mori 2016-11-09 10:23:55 -05:00
commit b957ebd795
71 changed files with 2628 additions and 1428 deletions

View File

@ -39,6 +39,7 @@ import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datasourceprocessors.RawDSProcessor;
/**
* visual component for the first panel of add image wizard. Allows the user to
@ -92,6 +93,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel {
datasourceProcessorsMap.remove(LocalDiskDSProcessor.getType());
}
coreDSPTypes.add(LocalFilesDSProcessor.getType());
coreDSPTypes.add(RawDSProcessor.getType());
for (String dspType : coreDSPTypes) {
typeComboBox.addItem(dspType);

View File

@ -78,7 +78,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
this.contextName = context;
createTimeZoneList();
}
/**
@ -89,6 +88,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters);
instance.postInit();
instance.createTimeZoneList();
return instance;
}

View File

@ -21,10 +21,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jPanel1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -39,11 +36,11 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jSplitPane1" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="panelDescriptionLabel" max="32767" attributes="0"/>
<Component id="jScrollPane2" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -55,7 +52,7 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="panelDescriptionLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jSplitPane1" max="32767" attributes="0"/>
<Component id="jScrollPane2" pref="458" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -69,6 +66,10 @@
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane2">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="jSplitPane1">
<Properties>
<Property name="dividerLocation" type="int" value="400"/>
@ -87,17 +88,17 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="1" max="32767" attributes="0"/>
<Component id="tagTypesListLabel" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="newTagNameButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="deleteTagNameButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="113" max="32767" attributes="0"/>
</Group>
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -105,11 +106,11 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="tagTypesListLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="383" max="32767" attributes="0"/>
<Component id="jScrollPane1" pref="381" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="newTagNameButton" alignment="3" min="-2" max="-2" attributes="0"/>
@ -186,12 +187,12 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="356" max="32767" attributes="0"/>
<EmptySpace min="0" pref="354" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="456" max="32767" attributes="0"/>
<EmptySpace min="0" pref="454" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -201,4 +202,6 @@
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -67,6 +67,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
jPanel1 = new javax.swing.JPanel();
panelDescriptionLabel = new javax.swing.JLabel();
jScrollPane2 = new javax.swing.JScrollPane();
jSplitPane1 = new javax.swing.JSplitPane();
modifyTagTypesListPanel = new javax.swing.JPanel();
tagTypesListLabel = new javax.swing.JLabel();
@ -111,13 +112,13 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
.addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(tagTypesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
.addComponent(newTagNameButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deleteTagNameButton)
.addGap(0, 113, Short.MAX_VALUE))
.addComponent(jScrollPane1))
.addGap(0, 113, Short.MAX_VALUE)))
.addContainerGap())
);
modifyTagTypesListPanelLayout.setVerticalGroup(
@ -126,7 +127,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
.addContainerGap()
.addComponent(tagTypesListLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 383, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 381, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(newTagNameButton)
@ -140,24 +141,26 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
tagTypesAdditionalPanel.setLayout(tagTypesAdditionalPanelLayout);
tagTypesAdditionalPanelLayout.setHorizontalGroup(
tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 356, Short.MAX_VALUE)
.addGap(0, 354, Short.MAX_VALUE)
);
tagTypesAdditionalPanelLayout.setVerticalGroup(
tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 456, Short.MAX_VALUE)
.addGap(0, 454, Short.MAX_VALUE)
);
jSplitPane1.setRightComponent(tagTypesAdditionalPanel);
jScrollPane2.setViewportView(jSplitPane1);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jSplitPane1)
.addComponent(panelDescriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(panelDescriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jScrollPane2))
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
@ -166,7 +169,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
.addContainerGap()
.addComponent(panelDescriptionLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSplitPane1)
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 458, Short.MAX_VALUE)
.addContainerGap())
);
@ -178,9 +181,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
@ -220,6 +221,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
private javax.swing.JButton deleteTagNameButton;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JPanel modifyTagTypesListPanel;
private javax.swing.JButton newTagNameButton;

View File

@ -141,7 +141,6 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.created"), ContentUtils.getStringTime(file.getCrtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.changed"), ContentUtils.getStringTime(file.getCtime(), file));
String md5 = file.getMd5Hash();
if (md5 == null) {
md5 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
@ -149,7 +148,6 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.md5"), md5);
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.hashLookupResults"), file.getKnown().toString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.internalid"), Long.toString(file.getId()));
if (file.getType().compareTo(TSK_DB_FILES_TYPE_ENUM.LOCAL) == 0) {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), file.getLocalAbsPath());
}

View File

@ -64,12 +64,54 @@ public class Installer extends ModuleInstall {
//Note: if shipping with a different CRT version, this will only print a warning
//and try to use linker mechanism to find the correct versions of libs.
//We should update this if we officially switch to a new version of CRT/compiler
System.loadLibrary("msvcr100"); //NON-NLS
System.loadLibrary("msvcp100"); //NON-NLS
System.loadLibrary("api-ms-win-core-console-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-datetime-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-debug-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-errorhandling-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-file-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-file-l1-2-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-file-l2-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-handle-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-heap-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-interlocked-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-libraryloader-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-localization-l1-2-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-memory-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-namedpipe-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-processenvironment-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-processthreads-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-processthreads-l1-1-1"); //NON-NLS
System.loadLibrary("api-ms-win-core-profile-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-rtlsupport-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-string-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-synch-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-synch-l1-2-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-sysinfo-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-timezone-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-core-util-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-conio-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-convert-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-environment-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-filesystem-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-heap-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-locale-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-math-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-multibyte-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-private-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-process-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-runtime-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-stdio-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-string-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-time-l1-1-0"); //NON-NLS
System.loadLibrary("api-ms-win-crt-utility-l1-1-0"); //NON-NLS
logger.log(Level.INFO, "MSVCR100 and MSVCP100 libraries loaded"); //NON-NLS
System.loadLibrary("ucrtbase"); //NON-NLS
System.loadLibrary("vcruntime140"); //NON-NLS
System.loadLibrary("msvcp140"); //NON-NLS
logger.log(Level.INFO, "Visual C Runtime libraries loaded"); //NON-NLS
} catch (UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error loading MSVCR100 and MSVCP100 libraries, ", e); //NON-NLS
logger.log(Level.SEVERE, "Error loading Visual C Runtime libraries, ", e); //NON-NLS
}
try {

View File

@ -34,7 +34,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Level;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
@ -56,11 +55,9 @@ import org.openide.nodes.NodeEvent;
import org.openide.nodes.NodeListener;
import org.openide.nodes.NodeMemberEvent;
import org.openide.nodes.NodeReorderEvent;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* DataResult sortable table viewer
@ -80,10 +77,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
private static final String DUMMY_NODE_DISPLAY_NAME = NbBundle.getMessage(DataResultViewerTable.class, "DataResultViewerTable.dummyNodeDisplayName");
private static final Color TAGGED_COLOR = new Color(230, 235, 240);
private Node currentRoot;
// The following two variables keep track of whether the user is trying
// to move the first column, which is not allowed.
private int oldColumnIndex = -1;
private int newColumnIndex = -1;
// When a column in the table is moved, these two variables keep track of where
// the column started and where it ended up.
private int startColumnIndex = -1;
private int endColumnIndex = -1;
/**
* Creates a DataResultViewerTable object that is compatible with node
@ -137,11 +134,19 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
if (fromIndex == toIndex) {
return;
}
// to keep track of attempts to move the first column
if (oldColumnIndex == -1) {
oldColumnIndex = fromIndex;
/* Because a column may be dragged to several different positions before
* the mouse is released (thus causing multiple TableColumnModelEvents to
* be fired), we want to keep track of the starting column index in this
* potential series of movements. Therefore we only keep track of the
* original fromIndex in startColumnIndex, but we always update
* endColumnIndex to know the final position of the moved column.
* See the MouseListener mouseReleased method.
*/
if (startColumnIndex == -1) {
startColumnIndex = fromIndex;
}
newColumnIndex = toIndex;
endColumnIndex = toIndex;
List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
Node.Property<?> prop = props.remove(fromIndex);
@ -158,10 +163,20 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
ov.getOutline().getTableHeader().addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (oldColumnIndex != -1 && (oldColumnIndex == 0 || newColumnIndex == 0)) {
ov.getOutline().moveColumn(newColumnIndex, oldColumnIndex);
/* If the startColumnIndex is not -1 (which is the reset value), that
* means columns have been moved around. We then check to see if either
* the starting or end position is 0 (the first column), and then swap
* them back if that is the case because we don't want to allow movement
* of the first column. We then reset startColumnIndex to -1, the reset
* value.
* We check if startColumnIndex is at reset or not because it is
* possible for the mouse to be released and a MouseEvent to be fired
* without having moved any columns.
*/
if (startColumnIndex != -1 && (startColumnIndex == 0 || endColumnIndex == 0)) {
ov.getOutline().moveColumn(endColumnIndex, startColumnIndex);
}
oldColumnIndex = -1;
startColumnIndex = -1;
}
});
}
@ -217,68 +232,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
private javax.swing.JScrollPane tableScrollPanel;
// End of variables declaration//GEN-END:variables
/**
* Gets regular Bean property set properties from first child of Node.
*
* @param parent Node with at least one child to get properties from
*
* @return Properties,
*/
private Node.Property<?>[] getChildPropertyHeaders(Node parent) {
Node firstChild = parent.getChildren().getNodeAt(0);
if (firstChild == null) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "DataResultViewerTable.illegalArgExc.noChildFromParent"));
} else {
for (PropertySet ps : firstChild.getPropertySets()) {
if (ps.getName().equals(Sheet.PROPERTIES)) {
return ps.getProperties();
}
}
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "DataResultViewerTable.illegalArgExc.childWithoutPropertySet"));
}
}
/**
* Gets regular Bean property set properties from all first children and,
* recursively, subchildren of Node. Note: won't work out the box for lazy
* load - you need to set all children props for the parent by hand
*
* @param parent Node with at least one child to get properties from
*
* @return Properties,
*/
@SuppressWarnings("rawtypes")
private Node.Property[] getAllChildPropertyHeaders(Node parent) {
Node firstChild = parent.getChildren().getNodeAt(0);
Property[] properties = null;
if (firstChild == null) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "DataResultViewerTable.illegalArgExc.noChildFromParent"));
} else {
Set<Property> allProperties = new LinkedHashSet<>();
while (firstChild != null) {
for (PropertySet ps : firstChild.getPropertySets()) {
final Property[] props = ps.getProperties();
final int propsNum = props.length;
for (int i = 0; i < propsNum; ++i) {
allProperties.add(props[i]);
}
}
firstChild = firstChild.getChildren().getNodeAt(0);
}
properties = allProperties.toArray(new Property<?>[0]);
}
return properties;
}
/**
* Gets regular Bean property set properties from all children and,
* recursively, subchildren of Node. Note: won't work out the box for lazy
@ -320,6 +273,11 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
@Override
public void setNode(Node selectedNode) {
final OutlineView ov = ((OutlineView) this.tableScrollPanel);
/* The quick filter must be reset because when determining column width,
* ETable.getRowCount is called, and the documentation states that quick
* filters must be unset for the method to work
* "If the quick-filter is applied the number of rows do not match the number of rows in the model."
*/
ov.getOutline().unsetQuickFilter();
// change the cursor to "waiting cursor" for this operation
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
@ -405,9 +363,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
// Just let the table resize itself.
ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS);
// get first row's values for the table
if (root.getChildren().getNodesCount() != 0) {
final Graphics graphics = ov.getGraphics();
if (graphics != null) {
final FontMetrics metrics = graphics.getFontMetrics();
@ -420,9 +376,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
int columnWidthLimit = (column == 0) ? 350 : 300;
int valuesWidth = 0;
// find the maximum width needed to fit the values for the first 15 rows, at most
// *15 is an arbitrary number
for (int row = 0; row < Math.min(15, ov.getOutline().getRowCount()); row++) {
// find the maximum width needed to fit the values for the first 100 rows, at most
for (int row = 0; row < Math.min(100, ov.getOutline().getRowCount()); row++) {
TableCellRenderer renderer = ov.getOutline().getCellRenderer(row, column);
Component comp = ov.getOutline().prepareRenderer(renderer, row, column);
valuesWidth = Math.max(comp.getPreferredSize().width, valuesWidth);
@ -438,6 +393,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
ov.getOutline().getColumnModel().getColumn(column).setPreferredWidth(columnWidth);
}
}
} else {
// if there's no content just auto resize all columns
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
}
/**
* This custom renderer extends the renderer that was already being
@ -480,9 +439,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
}
}
ov.getOutline().setDefaultRenderer(Object.class, new ColorTagCustomRenderer());
} else {
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
}
}
/**
@ -504,7 +460,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
List<Node.Property<?>> props = new ArrayList<>(propertiesAcc);
for (int i = 0; i < props.size(); i++) {
Property<?> prop = props.get(i);
NbPreferences.forModule(this.getClass()).put(getPreferenceKey(prop, tfn.getItemType()), String.valueOf(i));
NbPreferences.forModule(this.getClass()).put(getColumnPreferenceKey(prop, tfn.getColumnOrderKey()), String.valueOf(i));
}
}
@ -523,8 +479,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
if (currentRoot instanceof TableFilterNode) {
tfn = (TableFilterNode) currentRoot;
} else {
Logger.getLogger(DataResultViewerTable.class.getName()).log(Level.INFO,
"Node {0} is not a TableFilterNode, columns are going to be in default order", currentRoot.getName());
// The node is not a TableFilterNode, columns are going to be in default order
return props;
}
@ -535,8 +490,8 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
Map<Integer, Node.Property<?>> propsFromPreferences = new TreeMap<>();
int offset = props.size();
for (Property<?> prop : props) {
Integer value = Integer.valueOf(NbPreferences.forModule(this.getClass()).get(getPreferenceKey(prop, tfn.getItemType()), "-1"));
if (value >= 0) {
Integer value = Integer.valueOf(NbPreferences.forModule(this.getClass()).get(getColumnPreferenceKey(prop, tfn.getColumnOrderKey()), "-1"));
if (value >= 0 && value < offset) {
propsFromPreferences.put(value, prop);
} else {
propsFromPreferences.put(offset, prop);
@ -559,7 +514,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
* @param type The type of the current node
* @return A generated key for the preference file
*/
private String getPreferenceKey(Property<?> prop, String type) {
private String getColumnPreferenceKey(Property<?> prop, String type) {
return type.replaceAll("[^a-zA-Z0-9_]", "") + "."
+ prop.getName().replaceAll("[^a-zA-Z0-9_]", "") + ".column";
}

View File

@ -25,11 +25,13 @@ import org.openide.util.NbBundle;
/**
* A filter node that creates at most one layer of child nodes for the node it
* wraps. It is designed to be used for nodes displayed in Autopsy table views.
* This ensures that the table view for the node will not recursively display
* child nodes and display only the first layer of child nodes.
*/
public class TableFilterNode extends FilterNode {
private final boolean createChildren;
private String itemType = "NONE";
private String columnOrderKey = "NONE";
/**
* Constructs a filter node that creates at most one layer of child nodes
@ -39,6 +41,7 @@ public class TableFilterNode extends FilterNode {
* @param wrappedNode The node to wrap in the filter node.
* @param createChildren True if a children (child factory) object should be
* created for the wrapped node.
* The constructor should include column order key. (See getColumnOrderKey)
*/
public TableFilterNode(Node wrappedNode, boolean createChildren) {
super(wrappedNode, TableFilterChildren.createInstance(wrappedNode, createChildren));
@ -51,13 +54,14 @@ public class TableFilterNode extends FilterNode {
* @param wrappedNode The node to wrap in the filter node.
* @param createChildren True if a children (child factory) object should be
* created for the wrapped node.
* @param itemType A name of the node, based on its class name and
* filter or artifact type if it holds those.
* @param columnOrderKey A key that represents the type of the original
* wrapped node and what is being displayed under that
* node.
*/
public TableFilterNode(Node wrappedNode, boolean createChildren, String itemType) {
public TableFilterNode(Node wrappedNode, boolean createChildren, String columnOrderKey) {
super(wrappedNode, TableFilterChildren.createInstance(wrappedNode, createChildren));
this.createChildren = createChildren;
this.itemType = itemType;
this.columnOrderKey = columnOrderKey;
}
/**
@ -76,10 +80,13 @@ public class TableFilterNode extends FilterNode {
}
/**
* @return itemType of associated DisplayableItemNode to allow for custom
* column orderings in the DataResultViewerTable
* @return the column order key, which allows custom column ordering to be
* written into a properties file and be reloaded for future use in
* a table with the same root node or for different cases. This is
* done by DataResultViewerTable. The key should represent what
* kinds of items the table is showing.
*/
String getItemType() {
return itemType;
String getColumnOrderKey() {
return columnOrderKey;
}
}

View File

@ -130,14 +130,6 @@ public class ArtifactStringContent implements StringContent {
buffer.append("</td>"); //NON-NLS
buffer.append("</tr>\n"); //NON-NLS
// add artifact ID (useful for debugging)
buffer.append("<tr><td>"); //NON-NLS
buffer.append(NbBundle.getMessage(this.getClass(), "ArtifactStringContent.getStr.artifactId.text"));
buffer.append("</td><td>"); //NON-NLS
buffer.append(artifact.getArtifactID());
buffer.append("</td>"); //NON-NLS
buffer.append("</tr>\n"); //NON-NLS
buffer.append("</table>"); //NON-NLS
buffer.append("</html>\n"); //NON-NLS

View File

@ -18,8 +18,6 @@
*/
package org.sleuthkit.autopsy.datamodel.accounts;
import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel.AutopsyVisitableItem;
import com.google.common.collect.Range;
import com.google.common.collect.RangeMap;
import com.google.common.collect.TreeRangeMap;
@ -59,6 +57,8 @@ import org.openide.util.Utilities;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.datamodel.AutopsyItemVisitor;
import org.sleuthkit.autopsy.datamodel.AutopsyVisitableItem;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.CreditCards;
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
@ -76,6 +76,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData.DbType;
/**
* AutopsyVisitableItem for the Accounts section of the tree. All nodes,
@ -146,6 +147,14 @@ final public class Accounts implements AutopsyVisitableItem {
*/
private abstract class ObservingChildren<X> extends Children.Keys<X> {
/**
* Override of default constructor to force lazy creation of nodes, by
* concrete instances of ObservingChildren
*/
ObservingChildren() {
super(true);
}
/**
* Create of keys used by this Children object to represent the child
* nodes.
@ -167,6 +176,9 @@ final public class Accounts implements AutopsyVisitableItem {
@Subscribe
abstract void handleReviewStatusChange(ReviewStatusChangeEvent event);
@Subscribe
abstract void handleDataAdded(ModuleDataEvent event);
@Override
protected void removeNotify() {
super.removeNotify();
@ -219,7 +231,7 @@ final public class Accounts implements AutopsyVisitableItem {
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData
&& eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
refreshKeys();
reviewStatusBus.post(eventData);
}
} catch (IllegalStateException notUsed) {
// Case is closed, do nothing.
@ -250,7 +262,13 @@ final public class Accounts implements AutopsyVisitableItem {
@Subscribe
@Override
public void handleReviewStatusChange(ReviewStatusChangeEvent event) {
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
refreshKeys();
}
@Subscribe
@Override
void handleDataAdded(ModuleDataEvent event) {
refreshKeys();
}
@ -377,10 +395,17 @@ final public class Accounts implements AutopsyVisitableItem {
}
}
@Subscribe
@Override
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
refreshKeys();
}
@Subscribe
@Override
void handleDataAdded(ModuleDataEvent event) {
refreshKeys();
}
}
private DefaultAccountTypeNode(String accountTypeName) {
@ -426,10 +451,12 @@ final public class Accounts implements AutopsyVisitableItem {
*/
final private class ViewModeFactory extends ObservingChildren<CreditCardViewMode> {
@Subscribe
@Override
public void handleReviewStatusChange(ReviewStatusChangeEvent event) {
refreshKeys();
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
}
@Override
void handleDataAdded(ModuleDataEvent event) {
}
/**
@ -490,7 +517,13 @@ final public class Accounts implements AutopsyVisitableItem {
@Subscribe
@Override
public void handleReviewStatusChange(ReviewStatusChangeEvent event) {
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
refreshKeys();
}
@Subscribe
@Override
void handleDataAdded(ModuleDataEvent event) {
refreshKeys();
}
@ -499,10 +532,15 @@ final public class Accounts implements AutopsyVisitableItem {
List<FileWithCCN> list = new ArrayList<>();
String query
= "SELECT blackboard_artifacts.obj_id," //NON-NLS
+ " solr_attribute.value_text AS solr_document_id, " //NON-NLS
+ " GROUP_CONCAT(blackboard_artifacts.artifact_id) AS artifact_IDs, " //NON-NLS
+ " COUNT( blackboard_artifacts.artifact_id) AS hits, " //NON-NLS
+ " GROUP_CONCAT(blackboard_artifacts.review_status_id) AS review_status_ids "
+ " solr_attribute.value_text AS solr_document_id, "; //NON-NLS
if(skCase.getDatabaseType().equals(DbType.POSTGRESQL)){
query += " string_agg(blackboard_artifacts.artifact_id::character varying, ',') AS artifact_IDs, " //NON-NLS
+ " string_agg(blackboard_artifacts.review_status_id::character varying, ',') AS review_status_ids, ";
} else {
query += " GROUP_CONCAT(blackboard_artifacts.artifact_id) AS artifact_IDs, " //NON-NLS
+ " GROUP_CONCAT(blackboard_artifacts.review_status_id) AS review_status_ids, ";
}
query += " COUNT( blackboard_artifacts.artifact_id) AS hits " //NON-NLS
+ " FROM blackboard_artifacts " //NON-NLS
+ " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS
+ " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS
@ -571,12 +609,16 @@ final public class Accounts implements AutopsyVisitableItem {
+ " AND account_type.value_text = '" + Account.Type.CREDIT_CARD.name() + "'" //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ getRejectedArtifactFilterClause()
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text )";
+ " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
ResultSet rs = results.getResultSet();) {
while (rs.next()) {
if(skCase.getDatabaseType().equals(DbType.POSTGRESQL)){
setDisplayName(Bundle.Accounts_ByFileNode_displayName(rs.getLong("count")));
} else {
setDisplayName(Bundle.Accounts_ByFileNode_displayName(rs.getLong("count(*)")));
}
}
} catch (TskCoreException | SQLException ex) {
LOGGER.log(Level.SEVERE, "Error querying for files with ccn hits.", ex); //NON-NLS
@ -599,7 +641,12 @@ final public class Accounts implements AutopsyVisitableItem {
}
@Subscribe
public void handleReviewStatusChange(ReviewStatusChangeEvent event) {
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
updateDisplayName();
}
@Subscribe
void handleDataAdded(ModuleDataEvent event) {
updateDisplayName();
}
}
@ -617,7 +664,13 @@ final public class Accounts implements AutopsyVisitableItem {
@Subscribe
@Override
public void handleReviewStatusChange(ReviewStatusChangeEvent event) {
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
refreshKeys();
}
@Subscribe
@Override
void handleDataAdded(ModuleDataEvent event) {
refreshKeys();
}
@ -718,7 +771,12 @@ final public class Accounts implements AutopsyVisitableItem {
}
@Subscribe
public void handleReviewStatusChange(ReviewStatusChangeEvent event) {
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
updateDisplayName();
}
@Subscribe
void handleDataAdded(ModuleDataEvent event) {
updateDisplayName();
}
}
@ -960,15 +1018,18 @@ final public class Accounts implements AutopsyVisitableItem {
@Subscribe
@Override
public void handleReviewStatusChange(ReviewStatusChangeEvent event) {
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
refreshKeys();
//make sure to refresh the nodes for artifacts that changed statuses.
event.artifacts.stream().map(BlackboardArtifact::getArtifactID).forEach(this::refreshKey);
}
/**
*
*/
@Subscribe
@Override
void handleDataAdded(ModuleDataEvent event) {
refreshKeys();
}
@Override
protected List<Long> createKeys() {
List<Long> list = new ArrayList<>();
@ -979,7 +1040,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
+ " AND blackboard_attributes.value_text >= \"" + bin.getBINStart() + "\" AND blackboard_attributes.value_text < \"" + (bin.getBINEnd() + 1) + "\"" //NON-NLS
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
+ getRejectedArtifactFilterClause()
+ " ORDER BY blackboard_attributes.value_text"; //NON-NLS
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
@ -1010,12 +1071,11 @@ final public class Accounts implements AutopsyVisitableItem {
}
}
private final BinResult bin;
// private final CreditCardNumberFactory accountFactory;
private BINNode(BinResult bin) {
super(Children.LEAF);
setChildren(Children.createLazy(CreditCardNumberFactory::new));
this.bin = bin;
setChildren(Children.createLazy(CreditCardNumberFactory::new));
setName(getBinRangeString());
updateDisplayName();
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS
@ -1023,7 +1083,12 @@ final public class Accounts implements AutopsyVisitableItem {
}
@Subscribe
public void handleReviewStatusChange(ReviewStatusChangeEvent event) {
void handleReviewStatusChange(ReviewStatusChangeEvent event) {
updateDisplayName();
}
@Subscribe
void handleDataAdded(ModuleDataEvent event) {
updateDisplayName();
}
@ -1034,7 +1099,7 @@ final public class Accounts implements AutopsyVisitableItem {
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS
+ " AND blackboard_attributes.value_text >= \"" + bin.getBINStart() + "\" AND blackboard_attributes.value_text < \"" + (bin.getBINEnd() + 1) + "\"" //NON-NLS
+ " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
+ getRejectedArtifactFilterClause();
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
ResultSet rs = results.getResultSet();) {
@ -1334,18 +1399,27 @@ final public class Accounts implements AutopsyVisitableItem {
*/
if (newStatus == BlackboardArtifact.ReviewStatus.REJECTED && showRejected == false) {
List<Node> siblings = Arrays.asList(node.getParentNode().getChildren().getNodes());
if (siblings.size() > 1) {
int indexOf = siblings.indexOf(node);
//there is no previous for the first node, so instead we select the next one
Node sibling = indexOf > 0
? siblings.get(indexOf - 1)
: siblings.get(indexOf + 1);
: siblings.get(Integer.max(indexOf + 1, siblings.size() - 1));
createPath = NodeOp.createPath(sibling, null);
} else {
/* if there are no other siblings to select,
* just return null, but note we need to filter
* this out of stream below */
return null;
}
} else {
createPath = NodeOp.createPath(node, null);
}
//for the reselect to work we need to strip off the first part of the path.
return Arrays.copyOfRange(createPath, 1, createPath.length);
}).collect(Collectors.toList());
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
//change status of selected artifacts
final Collection<? extends BlackboardArtifact> artifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
@ -1392,7 +1466,7 @@ final public class Accounts implements AutopsyVisitableItem {
}
}
class ReviewStatusChangeEvent {
private class ReviewStatusChangeEvent {
Collection<? extends BlackboardArtifact> artifacts;
BlackboardArtifact.ReviewStatus newReviewStatus;

View File

@ -0,0 +1,183 @@
package org.sleuthkit.autopsy.datasourceprocessors;
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 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.
*/
import java.io.File;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
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;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskFileRange;
import org.openide.util.NbBundle.Messages;
/*
* A runnable that adds a raw data source to a case database.
*/
final class AddRawImageTask implements Runnable {
private static final Logger logger = Logger.getLogger(AddRawImageTask.class.getName());
private final String deviceId;
private final String imageFilePath;
private final String timeZone;
private final long chunkSize;
private final DataSourceProcessorProgressMonitor progressMonitor;
private final DataSourceProcessorCallback callback;
private boolean criticalErrorOccurred;
private static final long TWO_GB = 2000000000L;
/**
* Constructs a runnable that adds a raw data source to a 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 imageFilePath Path to a Raw data source file.
* @param timeZone The time zone to use when processing dates
* and times for the image, obtained from
* java.util.TimeZone.getID.
* @param breakupChunks 2GB or not breakup.
* @param progressMonitor Progress monitor for reporting
* progressMonitor during processing.
* @param callback Callback to call when processing is done.
*/
AddRawImageTask(String deviceId, String imageFilePath, String timeZone, long chunkSize, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
this.deviceId = deviceId;
this.imageFilePath = imageFilePath;
this.timeZone = timeZone;
this.chunkSize = chunkSize;
this.callback = callback;
this.progressMonitor = progressMonitor;
}
/**
* Adds a raw data source to a case database.
*/
@Override
public void run() {
/*
* Process the input image file.
*/
progressMonitor.setIndeterminate(true);
progressMonitor.setProgress(0);
List<Content> newDataSources = new ArrayList<>();
List<String> errorMessages = new ArrayList<>();
addImageToCase(newDataSources, errorMessages);
progressMonitor.setProgress(100);
/**
* Return the results via the callback passed to the constructor.
*/
DataSourceProcessorCallback.DataSourceProcessorResult result;
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);
criticalErrorOccurred = false;
}
/**
* Attempts to add the input image to the case.
*
* @param newDataSources If the image is added, a data source is added to
* this list for eventual return to the caller via the
* callback.
* @param errorMessages If there are any error messages, the error messages
* are added to this list for eventual return to the
* caller via the callback.
*/
@Messages({"AddRawImageTask.progress.add.text=Adding raw image: ",
"AddRawImageTask.image.critical.error.adding=Critical error adding ",
"AddRawImageTask.for.device=for device ",
"AddRawImageTask.image.notExisting=is not existing.",
"AddRawImageTask.image.noncritical.error.adding=Non-critical error adding "})
private void addImageToCase(List<Content> dataSources, List<String> errorMessages) {
progressMonitor.setProgressText(Bundle.AddRawImageTask_progress_add_text() + imageFilePath);
List<String> imageFilePaths = new ArrayList<>();
SleuthkitCase caseDatabase = Case.getCurrentCase().getSleuthkitCase();
caseDatabase.acquireExclusiveLock();
File imageFile = Paths.get(imageFilePath).toFile();
if (!imageFile.exists()) {
errorMessages.add(Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePath + Bundle.AddRawImageTask_for_device()
+ deviceId + Bundle.AddRawImageTask_image_notExisting());
criticalErrorOccurred = true;
return;
}
imageFilePaths.add(imageFilePath);
try {
/*
* Get Image that will be added to case
*/
Image dataSource = caseDatabase.addImageInfo(0, imageFilePaths, timeZone); //TODO: change hard coded deviceId.
dataSources.add(dataSource);
List<TskFileRange> fileRanges = new ArrayList<>();
/*
* Verify the size of the new image. Note that it may not be what is
* expected, but at least part of it was added to the case.
*/
String verificationError = dataSource.verifyImageSize();
if (!verificationError.isEmpty()) {
errorMessages.add(Bundle.AddRawImageTask_image_noncritical_error_adding() + imageFilePaths + Bundle.AddRawImageTask_for_device() + deviceId + ":" + verificationError);
}
long imageSize = dataSource.getSize();
int sequence = 0;
//start byte and end byte
long start = 0;
if (chunkSize > 0 && imageSize >= TWO_GB) {
for (double size = TWO_GB; size < dataSource.getSize(); size += TWO_GB) {
fileRanges.add(new TskFileRange(start, TWO_GB, sequence));
start += TWO_GB;
sequence++;
}
}
double leftoverSize = imageSize - sequence * TWO_GB;
fileRanges.add(new TskFileRange(start, (long)leftoverSize, sequence));
caseDatabase.addLayoutFiles(dataSource, fileRanges);
} catch (TskCoreException ex) {
errorMessages.add(Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePaths + Bundle.AddRawImageTask_for_device() + deviceId + ":" + ex.getLocalizedMessage());
criticalErrorOccurred = true;
} finally {
caseDatabase.releaseExclusiveLock();
}
}
}

View File

@ -0,0 +1,12 @@
# To change this license header, choose License Headers in Project Properties.
# To change this template file, choose Tools | Templates
# and open the template in the editor.
RawDSInputPanel.pathLabel.text=Browse for an unallocated space image file:
RawDSInputPanel.errorLabel.text=Error Label
RawDSInputPanel.browseButton.text=Browse
RawDSInputPanel.pathTextField.text=
RawDSInputPanel.jBreakFileUpLabel.text=Break image up into:
RawDSInputPanel.jNoBreakupRadioButton.text=Do not break up
RawDSInputPanel.j2GBBreakupRadioButton.text=2GB chunks
RawDSInputPanel.timeZoneLabel.text=Please select the input timezone:

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.ButtonGroup" name="infileTypeButtonGroup">
</Component>
</NonVisualComponents>
<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" alignment="0" attributes="0">
<Component id="pathTextField" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="browseButton" min="-2" pref="77" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pathLabel" min="-2" pref="218" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Component id="timeZoneLabel" min="-2" pref="168" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="timeZoneComboBox" min="-2" pref="199" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="19" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jBreakFileUpLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="errorLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="j2GBBreakupRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jNoBreakupRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" 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="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="timeZoneLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="timeZoneComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Component id="jBreakFileUpLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jNoBreakupRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="j2GBBreakupRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<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/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.pathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</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/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.pathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.browseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="j2GBBreakupRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="infileTypeButtonGroup"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.j2GBBreakupRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="j2GBBreakupRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jBreakFileUpLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.jBreakFileUpLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="jNoBreakupRadioButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="infileTypeButtonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.jNoBreakupRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jNoBreakupRadioButtonActionPerformed"/>
</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="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/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="timeZoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties" key="RawDSInputPanel.timeZoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="timeZoneComboBox">
<Properties>
<Property name="maximumRowCount" type="int" value="30"/>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,352 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 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.datasourceprocessors;
import java.io.File;
import java.util.Calendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
final class RawDSInputPanel extends JPanel implements DocumentListener {
private static final long TWO_GB = 2000000000L;
private static final long serialVersionUID = 1L; //default
private final String PROP_LASTINPUT_PATH = "LBL_LastInputFile_PATH";
private final JFileChooser fc = new JFileChooser();
// Externally supplied name is used to store settings
private final String contextName;
/**
* Creates new form RawDSInputPanel
*/
private RawDSInputPanel(String context) {
initComponents();
errorLabel.setVisible(false);
fc.setDragEnabled(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
this.contextName = context;
}
/**
* Creates and returns an instance of a RawDSInputPanel.
*/
static synchronized RawDSInputPanel createInstance(String context) {
RawDSInputPanel instance = new RawDSInputPanel(context);
instance.postInit();
instance.createTimeZoneList();
return instance;
}
//post-constructor initialization to properly initialize listener support
//without leaking references of uninitialized objects
private void postInit() {
pathTextField.getDocument().addDocumentListener(this);
}
/**
* Creates the drop down list for the time zones and then makes the local
* machine time zone to be selected.
*/
private void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
timeZoneComboBox.addItem(item);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
infileTypeButtonGroup = new javax.swing.ButtonGroup();
pathLabel = new javax.swing.JLabel();
pathTextField = new javax.swing.JTextField();
browseButton = new javax.swing.JButton();
j2GBBreakupRadioButton = new javax.swing.JRadioButton();
jBreakFileUpLabel = new javax.swing.JLabel();
jNoBreakupRadioButton = new javax.swing.JRadioButton();
errorLabel = new javax.swing.JLabel();
timeZoneLabel = new javax.swing.JLabel();
timeZoneComboBox = new javax.swing.JComboBox<>();
org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.pathLabel.text")); // NOI18N
pathTextField.setText(org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.pathTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.browseButton.text")); // NOI18N
browseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseButtonActionPerformed(evt);
}
});
infileTypeButtonGroup.add(j2GBBreakupRadioButton);
j2GBBreakupRadioButton.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(j2GBBreakupRadioButton, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.j2GBBreakupRadioButton.text")); // NOI18N
j2GBBreakupRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
j2GBBreakupRadioButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(jBreakFileUpLabel, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.jBreakFileUpLabel.text")); // NOI18N
infileTypeButtonGroup.add(jNoBreakupRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(jNoBreakupRadioButton, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.jNoBreakupRadioButton.text")); // NOI18N
jNoBreakupRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jNoBreakupRadioButtonActionPerformed(evt);
}
});
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.errorLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(RawDSInputPanel.class, "RawDSInputPanel.timeZoneLabel.text")); // NOI18N
timeZoneComboBox.setMaximumRowCount(30);
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, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pathLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 218, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addComponent(timeZoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 168, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 199, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGap(0, 19, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jBreakFileUpLabel)
.addComponent(errorLabel)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(j2GBBreakupRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jNoBreakupRadioButton)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, 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(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(browseButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(timeZoneLabel)
.addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(errorLabel)
.addGap(5, 5, 5)
.addComponent(jBreakFileUpLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jNoBreakupRadioButton)
.addComponent(j2GBBreakupRadioButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
@SuppressWarnings("deprecation")
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
String oldText = pathTextField.getText();
// set the current directory of the FileChooser if the ImagePath Field is valid
File currentDir = new File(oldText);
if (currentDir.exists()) {
fc.setCurrentDirectory(currentDir);
}
int retval = fc.showOpenDialog(this);
if (retval == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getPath();
pathTextField.setText(path);
}
}//GEN-LAST:event_browseButtonActionPerformed
private void j2GBBreakupRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_j2GBBreakupRadioButtonActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_j2GBBreakupRadioButtonActionPerformed
private void jNoBreakupRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jNoBreakupRadioButtonActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_jNoBreakupRadioButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.JLabel errorLabel;
private javax.swing.ButtonGroup infileTypeButtonGroup;
private javax.swing.JRadioButton j2GBBreakupRadioButton;
private javax.swing.JLabel jBreakFileUpLabel;
private javax.swing.JRadioButton jNoBreakupRadioButton;
private javax.swing.JLabel pathLabel;
private javax.swing.JTextField pathTextField;
private javax.swing.JComboBox<String> timeZoneComboBox;
private javax.swing.JLabel timeZoneLabel;
// End of variables declaration//GEN-END:variables
/**
* Get the path of the user selected image.
*
* @return the image path
*/
String getImageFilePath() {
return pathTextField.getText();
}
void reset() {
//reset the UI elements to default
pathTextField.setText(null);
j2GBBreakupRadioButton.setSelected(true);
}
long getChunkSize() {
if (jNoBreakupRadioButton.isSelected()) {
return -1;
} else { //if have more choices here, the selection of each radiobutton should be checked
return TWO_GB;
}
}
String getTimeZone() {
String tz = timeZoneComboBox.getSelectedItem().toString();
return tz.substring(tz.indexOf(")") + 2).trim();
}
/**
* Should we enable the next button of the wizard?
*
* @return true if a proper image has been selected, false otherwise
*/
boolean validatePanel() {
errorLabel.setVisible(false);
String path = getImageFilePath();
if (path == null || path.isEmpty()) {
return false;
}
// display warning if there is one (but don't disable "next" button)
warnIfPathIsInvalid(path);
boolean isExist = new File(path).exists();
return (isExist);
}
/**
* Validates path to selected data source and displays warning if it is
* invalid.
*
* @param path Absolute path to the selected data source
*/
@Messages({"RawDSInputPanel.error.text=Path to multi-user data source is on \"C:\" drive"})
private void warnIfPathIsInvalid(String path) {
if (!PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) {
errorLabel.setVisible(true);
errorLabel.setText(Bundle.RawDSInputPanel_error_text());
}
}
void storeSettings() {
String inFilePath = getImageFilePath();
if (null != inFilePath) {
String imagePath = inFilePath.substring(0, inFilePath.lastIndexOf(File.separator) + 1);
ModuleSettings.setConfigSetting(contextName, PROP_LASTINPUT_PATH, imagePath);
}
}
void readSettings() {
String inFilePath = ModuleSettings.getConfigSetting(contextName, PROP_LASTINPUT_PATH);
if (null != inFilePath) {
if (!inFilePath.isEmpty()) {
pathTextField.setText(inFilePath);
}
}
}
/**
* 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.
*
* @param e the event, which is ignored
*/
@Override
public void insertUpdate(DocumentEvent e) {
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
@Override
public void removeUpdate(DocumentEvent e) {
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
@Override
public void changedUpdate(DocumentEvent e) {
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
}
/**
* Set the focus to the pathTextField.
*/
void select() {
pathTextField.requestFocusInWindow();
}
}

View File

@ -0,0 +1,157 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 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.datasourceprocessors;
import java.util.UUID;
import javax.swing.JPanel;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
/**
* A Raw 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.
*/
@ServiceProvider(service = DataSourceProcessor.class)
public class RawDSProcessor implements DataSourceProcessor {
private final RawDSInputPanel configPanel;
private AddRawImageTask addImageTask;
/*
* Constructs a Raw 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 RawDSProcessor() {
configPanel = RawDSInputPanel.createInstance(RawDSProcessor.class.getName());
}
/**
* Gets a string that describes the type of data sources this processor is
* able to add to the case database. The string is suitable for display in a
* type selection UI component (e.g., a combo box).
*
* @return A data source type display string for this data source processor.
*/
@Messages({"RawDSProcessor.dataSourceType=Unallocated Space Image File"})
public static String getType() {
return Bundle.RawDSProcessor_dataSourceType();
}
/**
* Gets a string that describes the type of data sources this processor is
* able to add to the case database. The string is suitable for display in a
* type selection UI component (e.g., a combo box).
*
* @return A data source type display string for this data source processor.
*/
@Override
public String getDataSourceType() {
return Bundle.RawDSProcessor_dataSourceType();
}
/**
* 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) {
configPanel.storeSettings();
run(UUID.randomUUID().toString(), configPanel.getImageFilePath(), configPanel.getTimeZone(), configPanel.getChunkSize(), 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 rawDSInputFilePath Path to a Raw data source file.
* @param isHandsetFile Indicates whether the XML file is for a
* handset or a SIM.
* @param progressMonitor Progress monitor for reporting progress
* during processing.
*/
private void run(String deviceId, String imageFilePath, String timeZone, long chunkSize, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
addImageTask = new AddRawImageTask(deviceId, imageFilePath, timeZone, chunkSize, progressMonitor, callback);
new Thread(addImageTask).start();
}
@Override
public void cancel() {
}
/**
* Resets the selection and configuration panel for this data source
* processor.
*/
@Override
public void reset() {
configPanel.reset();
}
}

View File

@ -21,13 +21,32 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jSplitPane1" max="32767" attributes="0"/>
<Component id="externalViewerTitleLabel" max="32767" attributes="0"/>
<Component id="jPanel1" alignment="1" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jPanel1" alignment="1" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="externalViewerTitleLabel" pref="777" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="777" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
@ -36,9 +55,14 @@
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="externalViewerTitleLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="475" max="32767" attributes="0"/>
</Group>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jSplitPane1" pref="458" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</DimensionLayout>
@ -51,6 +75,10 @@
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="jSplitPane1">
<Properties>
<Property name="dividerLocation" type="int" value="350"/>
@ -75,7 +103,7 @@
<Component id="exePathLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="exePathNameLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="114" max="32767" attributes="0"/>
<EmptySpace pref="159" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -86,7 +114,7 @@
<Component id="exePathLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="exePathNameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="411" max="32767" attributes="0"/>
<EmptySpace pref="408" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -121,22 +149,25 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="ruleListLabel" alignment="1" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="rulesScrollPane" alignment="0" min="-2" pref="311" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="ruleListLabel" alignment="1" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="rulesScrollPane" min="-2" pref="311" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="newRuleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="editRuleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="deleteRuleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="18" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -146,14 +177,14 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="ruleListLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="rulesScrollPane" min="-2" pref="387" max="-2" attributes="0"/>
<Component id="rulesScrollPane" pref="380" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="newRuleButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="editRuleButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deleteRuleButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -229,4 +260,8 @@
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -78,7 +78,9 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
externalViewerTitleLabel = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
jSplitPane1 = new javax.swing.JSplitPane();
exePanel = new javax.swing.JPanel();
exePathLabel = new javax.swing.JLabel();
@ -111,7 +113,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme
.addGroup(exePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(exePathLabel)
.addComponent(exePathNameLabel))
.addContainerGap(114, Short.MAX_VALUE))
.addContainerGap(159, Short.MAX_VALUE))
);
exePanelLayout.setVerticalGroup(
exePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -120,7 +122,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme
.addComponent(exePathLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(exePathNameLabel)
.addContainerGap(411, Short.MAX_VALUE))
.addContainerGap(408, Short.MAX_VALUE))
);
jSplitPane1.setRightComponent(exePanel);
@ -160,18 +162,20 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme
.addGroup(rulesPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ruleListLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(rulesPanelLayout.createSequentialGroup()
.addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ruleListLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(rulesPanelLayout.createSequentialGroup()
.addComponent(rulesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 311, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
.addGroup(rulesPanelLayout.createSequentialGroup()
.addComponent(newRuleButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(editRuleButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deleteRuleButton)))
.addGap(0, 18, Short.MAX_VALUE)))
.addContainerGap())
.addComponent(deleteRuleButton)
.addGap(0, 0, Short.MAX_VALUE))))
);
rulesPanelLayout.setVerticalGroup(
rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -179,36 +183,55 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme
.addContainerGap()
.addComponent(ruleListLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(rulesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 387, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(rulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(newRuleButton)
.addComponent(editRuleButton)
.addComponent(deleteRuleButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
jSplitPane1.setLeftComponent(rulesPanel);
jScrollPane1.setViewportView(jSplitPane1);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(externalViewerTitleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 777, Short.MAX_VALUE)
.addContainerGap())
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 777, Short.MAX_VALUE)
.addContainerGap()))
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(externalViewerTitleLabel)
.addContainerGap(475, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(32, 32, 32)
.addComponent(jScrollPane1)
.addContainerGap()))
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jSplitPane1)
.addComponent(externalViewerTitleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
.addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(externalViewerTitleLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSplitPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 458, Short.MAX_VALUE)
.addContainerGap())
.addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
@ -334,6 +357,8 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme
private javax.swing.JLabel exePathLabel;
private javax.swing.JLabel exePathNameLabel;
private javax.swing.JLabel externalViewerTitleLabel;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JButton newRuleButton;
private javax.swing.JLabel ruleListLabel;

View File

@ -165,8 +165,9 @@ class FileSearchPanel extends javax.swing.JPanel {
contentList = Collections.<AbstractFile>emptyList();
}
SearchNode sn = new SearchNode(contentList);
final TopComponent searchResultWin = DataResultTopComponent.createInstance(title, pathText,
new TableFilterNode(new SearchNode(contentList), true), contentList.size());
new TableFilterNode(sn, true, sn.getName()), contentList.size());
searchResultWin.requestActive(); // make it the active top component

View File

@ -16,12 +16,12 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jPanel1" alignment="0" pref="838" max="32767" attributes="0"/>
<Component id="jPanel1" alignment="0" pref="817" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jPanel1" alignment="0" pref="500" max="32767" attributes="0"/>
<Component id="jPanel1" alignment="0" pref="526" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -38,7 +38,7 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
<Component id="jScrollPane1" pref="797" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -47,7 +47,7 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
<Component id="jScrollPane1" pref="504" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -79,6 +79,7 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane2" alignment="0" pref="0" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
@ -90,7 +91,6 @@
</Group>
<EmptySpace min="0" pref="191" max="32767" attributes="0"/>
</Group>
<Component id="jScrollPane2" alignment="0" pref="409" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@ -102,7 +102,7 @@
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane2" pref="401" max="32767" attributes="0"/>
<Component id="jScrollPane2" pref="427" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="newTypeButton" alignment="3" min="-2" max="-2" attributes="0"/>
@ -175,7 +175,7 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane3" pref="0" max="32767" attributes="0"/>
@ -188,7 +188,7 @@
<Component id="removeExtButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="40" max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
@ -201,7 +201,7 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="extHeaderLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane3" pref="401" max="32767" attributes="0"/>
<Component id="jScrollPane3" pref="427" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="newExtButton" alignment="3" min="-2" max="-2" attributes="0"/>

View File

@ -188,6 +188,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel
.addGroup(mimePanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addGroup(mimePanelLayout.createSequentialGroup()
.addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1)
@ -195,8 +196,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel
.addComponent(newTypeButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(removeTypeButton)))
.addGap(0, 191, Short.MAX_VALUE))
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 409, Short.MAX_VALUE))
.addGap(0, 191, Short.MAX_VALUE)))
.addContainerGap())
);
mimePanelLayout.setVerticalGroup(
@ -205,7 +205,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel
.addContainerGap()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 401, Short.MAX_VALUE)
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(newTypeButton)
@ -251,7 +251,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel
.addComponent(newExtButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(removeExtButton)))
.addGap(0, 40, Short.MAX_VALUE)))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
extensionPanelLayout.setVerticalGroup(
@ -260,7 +260,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel
.addContainerGap()
.addComponent(extHeaderLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 401, Short.MAX_VALUE)
.addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(newExtButton)
@ -278,14 +278,14 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 797, Short.MAX_VALUE)
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 504, Short.MAX_VALUE)
.addContainerGap())
);
@ -293,11 +293,11 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 838, Short.MAX_VALUE)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 817, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 526, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents

View File

@ -28,12 +28,10 @@ FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.message
FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.title=Missing Interesting Files Set Name
FileTypeIdGlobalSettingsPanel.JOptionPane.storeFailed.title=Save Failed
FileTypeIdGlobalSettingsPanel.JOptionPane.loadFailed.title=Load Failed
FileTypeIdGlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to file type definitions when ingest is running!
FileTypeIdGlobalSettingsPanel.loadFileTypes.errorMessage=Failed to load existing file type definitions.
FileTypeIdGlobalSettingsPanel.saveFileTypes.errorMessage=Failed to save file type definitions.
FileTypeIdGlobalSettingsPanel.newTypeButton.text=New Type
FileTypeIdGlobalSettingsPanel.jLabel2.text=Custom MIME Types:
FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy can automatically detect many file types. Add your custom file types here.
FileTypeIdGlobalSettingsPanel.startUp.fileTypeDetectorInitializationException.msg=Error initializing the file type detector.
AddFileTypeSignaturePanel.offsetLabel.text=Byte Offset
AddFileTypeSignaturePanel.signatureTextField.text=
@ -53,3 +51,5 @@ AddFileTypePanel.addSigButton.text=Add Signature
AddFileTypePanel.postHitCheckBox.text=Alert as an "Interesting File" when found
AddFileTypePanel.setNameLabel.text=Set Name
AddFileTypePanel.setNameTextField.text=
FileTypeIdGlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to file type definitions when ingest is running!
FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy can automatically detect many file types. Add your custom file types here.

View File

@ -9,7 +9,6 @@ FileTypeIdModuleFactory.createFileIngestModule.exception.msg=\u8a2d\u5b9a\u3092\
FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.toolTipText=\u65e2\u77e5\u306e\u30cf\u30c3\u30b7\u30e5\u5024\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u6570\u306b\u3088\u3063\u3066\u306f\u3001\u3053\u306e\u30dc\u30c3\u30af\u30b9\u3092\u9078\u629e\u3059\u308b\u3053\u3068\u306b\u3088\u308a\u3001\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u306e\u7279\u5b9a\u3092\u52a0\u901f\u3057\u307e\u3059\u3002
FileTypeIdIngestJobSettingsPanel.skipKnownCheckBox.text=\u65e2\u77e5\u30d5\u30a1\u30a4\u30eb\uff08NSRL\uff09\u3092\u30b9\u30ad\u30c3\u30d7
FileTypeIdGlobalSettingsPanel.deleteTypeButton.text=\u524a\u9664
FileTypeIdGlobalSettingsPanel.ingestRunningWarningLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u5b9f\u884c\u4e2d\u306b\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u5b9a\u7fa9\u3092\u5909\u66f4\u3067\u304d\u307e\u305b\u3093\uff01
FileTypeIdGlobalSettingsPanel.JOptionPane.invalidInterestingFilesSetName.title=\u7591\u308f\u3057\u3044\u30d5\u30a1\u30a4\u30eb\u30bb\u30c3\u30c8\u540d\u304c\u6b20\u3051\u3066\u3044\u307e\u3059
FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.message=MIME\u30bf\u30a4\u30d7\u304c\u5fc5\u8981\u3067\u3059\u3002
FileTypeIdGlobalSettingsPanel.JOptionPane.invalidMIMEType.title=MIME\u30bf\u30a4\u30d7\u304c\u6b20\u3051\u3066\u3044\u307e\u3059
@ -33,10 +32,11 @@ FileTypeIdGlobalSettingsPanel.offsetComboBox.startItem=\u958b\u59cb
FileTypeIdGlobalSettingsPanel.offsetComboBox.endItem=\u505c\u6b62
FileTypeIdGlobalSettingsPanel.JOptionPane.invalidOffset.length=\u30aa\u30d5\u30bb\u30c3\u30c8\u306f\u30b7\u30b0\u30cd\u30c1\u30e3\u30b5\u30a4\u30ba\u3088\u308a\u5c0f\u3055\u304f\u3066\u306f\u3044\u3051\u307e\u305b\u3093\u3002
FileTypeIdGlobalSettingsPanel.jLabel2.text=MIME\u30bf\u30a4\u30d7\uff1a
FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy\u306f\u81ea\u52d5\u7684\u306b\u591a\u304f\u306e\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u3092\u691c\u77e5\u3067\u304d\u307e\u3059\u3002\u3053\u3053\u306b\u306f\u3042\u306a\u305f\u306e\u30ab\u30b9\u30bf\u30e0\u306e\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002
FileTypeIdGlobalSettingsPanel.startUp.fileTypeDetectorInitializationException.msg=\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u30c7\u30a3\u30c6\u30af\u30bf\u3092\u8d77\u52d5\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
AddFileTypeSignaturePanel.signatureTypeLabel.text=\u30b7\u30b0\u30cd\u30c1\u30e3\u30bf\u30a4\u30d7
AddFileTypeSignaturePanel.signatureLabel.text=\u30b7\u30b0\u30cd\u30c1\u30e3
AddFileTypeSignaturePanel.offsetRelativeToLabel.text=\u30aa\u30d5\u30bb\u30c3\u30c8\u306f\u6b21\u3068\u76f8\u5bfe\u7684
AddFileTypeSignaturePanel.offsetLabel.text=\u30d0\u30a4\u30c8\u30aa\u30d5\u30bb\u30c3\u30c8
AddFileTypePanel.mimeTypeLabel.text=MIME\u30bf\u30a4\u30d7
FileTypeIdGlobalSettingsPanel.ingestRunningWarningLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u5b9f\u884c\u4e2d\u306b\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u5b9a\u7fa9\u3092\u5909\u66f4\u3067\u304d\u307e\u305b\u3093\uff01
FileTypeIdGlobalSettingsPanel.jLabel3.text=Autopsy\u306f\u81ea\u52d5\u7684\u306b\u591a\u304f\u306e\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u3092\u691c\u77e5\u3067\u304d\u307e\u3059\u3002\u3053\u3053\u306b\u306f\u3042\u306a\u305f\u306e\u30ab\u30b9\u30bf\u30e0\u306e\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002

View File

@ -51,14 +51,6 @@
</Properties>
</Component>
</NonVisualComponents>
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[700, 500]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[750, 500]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
@ -74,15 +66,12 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane2" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane2" alignment="0" pref="789" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="jScrollPane2" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane2" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -156,7 +145,7 @@
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hashDatabasesLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="createDatabaseButton" min="-2" pref="121" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="importDatabaseButton" min="-2" pref="132" max="-2" attributes="0"/>
@ -167,7 +156,6 @@
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -225,8 +213,9 @@
<Component id="sendIngestMessagesCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="ingestWarningLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="jScrollPane1" min="-2" pref="423" max="-2" attributes="0"/>
<Component id="jScrollPane1" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
@ -234,7 +223,7 @@
<Component id="importDatabaseButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="deleteDatabaseButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="29" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View File

@ -527,9 +527,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
jButton3.setFont(jButton3.getFont().deriveFont(jButton3.getFont().getStyle() & ~java.awt.Font.BOLD, 14));
org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.jButton3.text")); // NOI18N
setMinimumSize(new java.awt.Dimension(700, 500));
setPreferredSize(new java.awt.Dimension(750, 500));
ingestWarningLabel.setFont(ingestWarningLabel.getFont().deriveFont(ingestWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashLookupSettingsPanel.class, "HashLookupSettingsPanel.ingestWarningLabel.text")); // NOI18N
@ -712,8 +709,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 132, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 131, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
.addGap(0, 0, Short.MAX_VALUE))))
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -759,14 +755,15 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addGap(18, 18, 18)
.addComponent(sendIngestMessagesCheckBox)
.addGap(18, 18, 18)
.addComponent(ingestWarningLabel))
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 423, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(ingestWarningLabel)
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(jScrollPane1))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(createDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(29, Short.MAX_VALUE))
.addContainerGap())
);
jScrollPane2.setViewportView(jPanel1);
@ -775,13 +772,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane2)
.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 789, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane2)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents

View File

@ -29,7 +29,7 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" pref="762" max="32767" attributes="0"/>
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">

View File

@ -901,7 +901,7 @@ final class InterestingItemDefsPanel extends IngestModuleGlobalSettingsPanel imp
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 762, Short.MAX_VALUE)
.addComponent(jScrollPane1)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

View File

@ -1,6 +1,5 @@
VMExtractorIngestModuleFactory.moduleDisplayName=Virtual Machine Extractor
VMExtractorIngestModuleFactory.moduleDescription=Extracts virtual machine files and adds them to a case as data sources.
VMExtractorIngestModuleFactory.version=1.0
VMExtractorIngestModule.addedVirtualMachineImage.message=Added virtual machine image {0}
VMExtractorIngestModule.searchingImage.message=Searching image for virtual machine files
VMExtractorIngestModule.exportingToDisk.message=Exporting virtual machine files to disk

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.modules.vmextractor;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
@ -53,7 +54,7 @@ public final class VMExtractorIngestModuleFactory extends IngestModuleFactoryAda
@Override
public String getModuleVersionNumber() {
return NbBundle.getMessage(this.getClass(), "VMExtractorIngestModuleFactory.version");
return Version.getVersion();
}
@Override

View File

@ -170,6 +170,8 @@ class ReportGenerator {
TableReportGenerator generator = new TableReportGenerator(artifactTypeSelections, tagNameSelections, progressPanel, tableReport);
generator.execute();
tableReport.endReport();
// finish progress, wrap up
progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE);
errorList = generator.getErrorList();
});
worker.execute();

View File

@ -114,9 +114,6 @@ class TableReportGenerator {
// report on the tagged images
makeThumbnailTable();
}
// finish progress, wrap up
progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE);
}
/**
@ -1495,6 +1492,9 @@ class TableReportGenerator {
} else if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
columns.add(new StatusColumn());
attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE));
attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
attributeTypeSet.remove(new Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID));
} else {
// This is the case that it is a custom type. The reason an else is
// necessary is to make sure that the source file column is added

View File

@ -16,7 +16,7 @@
<dependency conf="autopsy_core->*" org="org.jbundle.thin.base.screen" name="jcalendarbutton" rev="1.4.6"/>
<!-- commmon -->
<dependency org="com.google.guava" name="guava" rev="18.0"/>
<dependency org="com.google.guava" name="guava" rev="19.0"/>
<dependency conf="autopsy_core->*" org="org.apache.commons" name="commons-lang3" rev="3.0"/>
<dependency conf="autopsy_core->*" org="org.apache.commons" name="commons-csv" rev="1.4"/>

View File

@ -22,7 +22,7 @@ file.reference.dom4j-1.6.1.jar=release/modules/ext/dom4j-1.6.1.jar
file.reference.geronimo-jms_1.1_spec-1.0.jar=release/modules/ext/geronimo-jms_1.1_spec-1.0.jar
file.reference.gson-1.4.jar=release/modules/ext/gson-1.4.jar
file.reference.gstreamer-java-1.5.jar=release/modules/ext/gstreamer-java-1.5.jar
file.reference.guava-18.0.jar=release/modules/ext/guava-18.0.jar
file.reference.guava-19.0.jar=release/modules/ext/guava-19.0.jar
file.reference.imageio-bmp-3.2.jar=release/modules/ext/imageio-bmp-3.2.jar
file.reference.imageio-core-3.2.jar=release/modules/ext/imageio-core-3.2.jar
file.reference.imageio-icns-3.2.jar=release/modules/ext/imageio-icns-3.2.jar
@ -75,7 +75,7 @@ javac.compilerargs=-Xlint -Xlint:-serial
javadoc.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-javadoc.jar
javadoc.reference.compiler-0.9.1.jar=release/modules/ext/compiler-0.9.1-javadoc.jar
javadoc.reference.controlsfx-8.40.11.jar=release/modules/ext/controlsfx-8.40.11-javadoc.jar
javadoc.reference.guava-18.0.jar=release/modules/ext/guava-18.0-javadoc.jar
javadoc.reference.guava-19.0.jar=release/modules/ext/guava-19.0-javadoc.jar
javadoc.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-javadoc.jar
javadoc.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-javadoc.jar
javadoc.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-javadoc.jar
@ -83,7 +83,7 @@ nbm.needs.restart=true
source.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-sources.jar
source.reference.compiler-0.9.1.jar=release/modules/ext/compiler-0.9.1-sources.jar
source.reference.controlsfx-8.40.11.jar=release/modules/ext/controlsfx-8.40.11-sources.jar
source.reference.guava-18.0.jar=release/modules/ext/guava-18.0-sources.jar
source.reference.guava-19.0.jar=release/modules/ext/guava-19.0-sources.jar
source.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4-sources.jar
source.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4-sources.jar
source.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-sources.jar

View File

@ -743,10 +743,6 @@
<runtime-relative-path>ext/mail-1.4.3.jar</runtime-relative-path>
<binary-origin>release/modules/ext/mail-1.4.3.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/guava-18.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/guava-18.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/imageio-tga-3.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/imageio-tga-3.2.jar</binary-origin>
@ -851,6 +847,10 @@
<runtime-relative-path>ext/slf4j-simple-1.6.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/slf4j-simple-1.6.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/guava-19.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/guava-19.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/imageio-bmp-3.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/imageio-bmp-3.2.jar</binary-origin>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,47 +19,73 @@
package org.sleuthkit.autopsy.keywordsearch;
import java.nio.charset.Charset;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException;
/**
* Represents each string chunk to be indexed, a derivative of TextExtractor
* file
* A representation of a chunk of text from a file that can be used, when
* supplied with an Ingester, to index the chunk for search.
*/
class AbstractFileChunk {
final class AbstractFileChunk {
private int chunkID;
private TextExtractor parent;
private final int chunkNumber;
private final TextExtractor textExtractor;
AbstractFileChunk(TextExtractor parent, int chunkID) {
this.parent = parent;
this.chunkID = chunkID;
}
public TextExtractor getParent() {
return parent;
}
public int getChunkId() {
return chunkID;
/**
* Constructs a representation of a chunk of text from a file that can be
* used, when supplied with an Ingester, to index the chunk for search.
*
* @param textExtractor A TextExtractor for the file.
* @param chunkNumber A sequence number for the chunk.
*/
AbstractFileChunk(TextExtractor textExtractor, int chunkNumber) {
this.textExtractor = textExtractor;
this.chunkNumber = chunkNumber;
}
/**
* return String representation of the absolute id (parent and child)
* Gets the TextExtractor for the source file of the text chunk.
*
* @return
* @return A reference to the TextExtractor.
*/
String getIdString() {
return Server.getChunkIdString(this.parent.getSourceFile().getId(), this.chunkID);
TextExtractor getTextExtractor() {
return textExtractor;
}
void index(Ingester ingester, byte[] content, long contentSize, Charset indexCharset) throws IngesterException {
ByteContentStream bcs = new ByteContentStream(content, contentSize, parent.getSourceFile(), indexCharset);
/**
* Gets the sequence number of the text chunk.
*
* @return The chunk number.
*/
int getChunkNumber() {
return chunkNumber;
}
/**
* Gets the id of the text chunk.
*
* @return An id of the form [source file object id]_[chunk number]
*/
String getChunkId() {
return Server.getChunkIdString(this.textExtractor.getSourceFile().getId(), this.chunkNumber);
}
/**
* Indexes the text chunk.
*
* @param ingester An Ingester to do the indexing.
* @param chunkBytes The raw bytes of the text chunk.
* @param chunkSize The size of the text chunk in bytes.
* @param charSet The char set to use during indexing.
*
* @throws org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException
*/
void index(Ingester ingester, byte[] chunkBytes, long chunkSize, Charset charSet) throws IngesterException {
ByteContentStream bcs = new ByteContentStream(chunkBytes, chunkSize, textExtractor.getSourceFile(), charSet);
try {
ingester.ingest(this, bcs, content.length);
} catch (Exception ingEx) {
throw new IngesterException(NbBundle.getMessage(this.getClass(), "AbstractFileChunk.index.exception.msg",
parent.getSourceFile().getId(), chunkID), ingEx);
ingester.ingest(this, bcs, chunkBytes.length);
} catch (Exception ex) {
throw new IngesterException(String.format("Error ingesting (indexing) file chunk: %s", getChunkId()), ex);
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -25,7 +25,6 @@ import java.io.Reader;
import java.nio.charset.Charset;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.apache.solr.common.util.ContentStream;
import org.sleuthkit.datamodel.AbstractContent;
import org.sleuthkit.datamodel.AbstractFile;
@ -36,11 +35,10 @@ import org.sleuthkit.datamodel.AbstractFile;
class AbstractFileStringContentStream implements ContentStream {
//input
private AbstractFile content;
private Charset charset;
private final AbstractFile content;
private final Charset charset;
//converted
private InputStream stream;
private static Logger logger = Logger.getLogger(AbstractFileStringContentStream.class.getName());
private final InputStream stream;
public AbstractFileStringContentStream(AbstractFile content, Charset charset, InputStream inputStream) {
this.content = content;

View File

@ -157,7 +157,6 @@ DropdownSearchPanel.cutMenuItem.text=Cut
DropdownSearchPanel.selectAllMenuItem.text=Select All
DropdownSearchPanel.pasteMenuItem.text=Paste
DropdownSearchPanel.copyMenuItem.text=Copy
AbstractFileChunk.index.exception.msg=Problem ingesting file string chunk\: {0}, chunk\: {1}
AbstractFileStringContentStream.getSize.exception.msg=Cannot tell how many chars in converted string, until entire string is converted
AbstractFileStringContentStream.getSrcInfo.text=File\:{0}
ByteContentStream.getSrcInfo.text=File\:{0}
@ -187,7 +186,6 @@ Ingester.FscContentStream.getSrcInfo=File\:{0}
Ingester.FscContentStream.getReader=Not supported yet.
Ingester.NullContentStream.getSrcInfo.text=File\:{0}
Ingester.NullContentStream.getReader=Not supported yet.
Keyword.toString.text=Keyword'{'query\={0}, isLiteral\={1}, keywordType\={2}'}'
KeywordSearch.moduleErr=Module Error
KeywordSearch.fireNumIdxFileChg.moduleErr.msg=A module caused an error listening to KeywordSearch updates. See log to determine which module. Some data could be incomplete.
KeywordSearchListsEncase.save.exception.msg=Not supported yet.

View File

@ -133,7 +133,6 @@ OptionsCategory_Keywords_KeywordSearchOptions=\u30ad\u30fc\u30ef\u30fc\u30c9\u69
ExtractedContentPanel.pageOfLabel.text=of
ExtractedContentPanel.pageCurLabel.text=-
ExtractedContentPanel.pageTotalLabel.text=-
AbstractFileChunk.index.exception.msg=\u30d5\u30a1\u30a4\u30eb\u30b9\u30c8\u30ea\u30f3\u30b0\u30c1\u30e3\u30f3\u30af\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u4e2d\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0}, \u30c1\u30e3\u30f3\u30af\: {1}
AbstractFileStringContentStream.getSize.exception.msg=\u30b9\u30c8\u30ea\u30f3\u30b0\u5168\u4f53\u304c\u5909\u63db\u3055\u308c\u306a\u3051\u308c\u3070\u3001\u5909\u63db\u3055\u308c\u305f\u30b9\u30c8\u30ea\u30f3\u30b0\u5185\u306e\u30ad\u30e3\u30e9\u30af\u30bf\u30fc\u6570\u306f\u4e0d\u660e\u3067\u3059\u3002
AbstractFileStringContentStream.getSrcInfo.text=\u30d5\u30a1\u30a4\u30eb\uff1a{0}
ByteContentStream.getSrcInfo.text=\u30d5\u30a1\u30a4\u30eb\uff1a{0}
@ -208,7 +207,6 @@ KeywordSearchIngestModule.doInBackGround.pendingMsg=\uff08\u30da\u30f3\u30c7\u30
SearchRunner.doInBackGround.cancelMsg=\uff08\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026\uff09
Server.addDoc.exception.msg2=\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u30cf\u30f3\u30c9\u30e9\u30fc\u3092\u4f7f\u7528\u3057\u307e\u3057\u305f\u304c\u3001\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306b\u6b21\u306e\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0}
ExtractedContentViewer.getSolrContent.txtBodyItal=<span style\=''font-style\:italic''>{0}</span>
Keyword.toString.text=Keyword'{'query\={0}, isLiteral\={1}, keywordType\={2}'}'
KeywordSearchJobSettingsPanel.keywordSearchEncodings.text=-
KeywordSearchJobSettingsPanel.languagesValLabel.text=-
KeywordSearchJobSettingsPanel.encodingsLabel.text=\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\uff1a

View File

@ -562,8 +562,8 @@ class DropdownListSearchPanel extends KeywordSearchPanel {
Boolean regex;
KeywordTableEntry(Keyword keyword) {
this.name = keyword.getQuery();
this.regex = !keyword.isLiteral();
this.name = keyword.getSearchTerm();
this.regex = !keyword.searchTermIsLiteral();
}
@Override

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.keywordsearch;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
@ -27,11 +26,15 @@ import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JMenuItem;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* A simple UI for finding text after ingest
* A dropdown panel that provides GUI components that allow a user to do three
* types of ad hoc single keyword searches. The first option is a standard
* Lucene query for one or more terms, with or without wildcards and explicit
* Boolean operators, or a phrase. The second option is a Lucene query for a
* substring of a single term. The third option is a regex query using first the
* terms component, followed by standard Lucene queries for any terms found.
*
* The toolbar uses a different font from the rest of the application,
* Monospaced 14, due to the necessity to find a font that displays both Arabic
@ -39,38 +42,53 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* perform this task at the desired size, and neither could numerous other
* fonts.
*/
public class DropdownSingleTermSearchPanel extends KeywordSearchPanel {
public class DropdownSingleKeywordSearchPanel extends KeywordSearchPanel {
private static final Logger logger = Logger.getLogger(DropdownSingleTermSearchPanel.class.getName());
private static DropdownSingleTermSearchPanel instance = null;
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(DropdownSingleKeywordSearchPanel.class.getName());
private static DropdownSingleKeywordSearchPanel defaultInstance = null;
/**
* Creates new form DropdownSingleTermSearchPanel
* Gets the default instance of a dropdown panel that provides GUI
* components that allow a user to do three types of ad hoc single keyword
* searches.
*/
public DropdownSingleTermSearchPanel() {
public static synchronized DropdownSingleKeywordSearchPanel getDefault() {
if (null == defaultInstance) {
defaultInstance = new DropdownSingleKeywordSearchPanel();
}
return defaultInstance;
}
/**
* Constructs a dropdown panel that provides GUI components that allow a
* user to do three types of ad hoc single keyword searches.
*/
public DropdownSingleKeywordSearchPanel() {
initComponents();
customizeComponents();
}
/**
* Does additional initialization of the GUI components created by the
* initComponents method.
*/
private void customizeComponents() {
keywordTextField.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
//do nothing
}
@Override
public void focusLost(FocusEvent e) {
if (keywordTextField.getText().equals("")) {
resetSearchBox();
clearSearchBox();
}
}
});
keywordTextField.setComponentPopupMenu(rightClickMenu);
ActionListener actList = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ActionListener actList = (ActionEvent e) -> {
JMenuItem jmi = (JMenuItem) e.getSource();
if (jmi.equals(cutMenuItem)) {
keywordTextField.cut();
@ -81,7 +99,6 @@ public class DropdownSingleTermSearchPanel extends KeywordSearchPanel {
} else if (jmi.equals(selectAllMenuItem)) {
keywordTextField.selectAll();
}
}
};
cutMenuItem.addActionListener(actList);
copyMenuItem.addActionListener(actList);
@ -89,36 +106,43 @@ public class DropdownSingleTermSearchPanel extends KeywordSearchPanel {
selectAllMenuItem.addActionListener(actList);
}
public static synchronized DropdownSingleTermSearchPanel getDefault() {
if (instance == null) {
instance = new DropdownSingleTermSearchPanel();
}
return instance;
}
/**
* Add an action listener to the Search buttom component of the panel.
*
* @param actionListener The actin listener.
*/
void addSearchButtonActionListener(ActionListener actionListener) {
searchButton.addActionListener(actionListener);
}
void resetSearchBox() {
/**
* Clears the text in the query text field, i.e., sets it to the emtpy
* string.
*/
void clearSearchBox() {
keywordTextField.setText("");
}
/**
* Gets a single keyword list consisting of a single keyword encapsulating
* the input term(s)/phrase/substring/regex.
*
* @return The keyword list.
*/
@Override
List<KeywordList> getKeywordLists() {
List<Keyword> keywords = new ArrayList<>();
keywords.add(new Keyword(keywordTextField.getText(),
!regexRadioButton.isSelected(), exactRadioButton.isSelected()));
keywords.add(new Keyword(keywordTextField.getText(), !regexRadioButton.isSelected(), exactRadioButton.isSelected()));
List<KeywordList> keywordLists = new ArrayList<>();
keywordLists.add(new KeywordList(keywords));
return keywordLists;
}
/**
* Not implemented.
*/
@Override
protected void postFilesIndexedChange() {
//nothing to update
}
/**
@ -142,20 +166,20 @@ public class DropdownSingleTermSearchPanel extends KeywordSearchPanel {
substringRadioButton = new javax.swing.JRadioButton();
regexRadioButton = new javax.swing.JRadioButton();
org.openide.awt.Mnemonics.setLocalizedText(cutMenuItem, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.cutMenuItem.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(cutMenuItem, org.openide.util.NbBundle.getMessage(DropdownSingleKeywordSearchPanel.class, "DropdownSearchPanel.cutMenuItem.text")); // NOI18N
rightClickMenu.add(cutMenuItem);
org.openide.awt.Mnemonics.setLocalizedText(copyMenuItem, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.copyMenuItem.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(copyMenuItem, org.openide.util.NbBundle.getMessage(DropdownSingleKeywordSearchPanel.class, "DropdownSearchPanel.copyMenuItem.text")); // NOI18N
rightClickMenu.add(copyMenuItem);
org.openide.awt.Mnemonics.setLocalizedText(pasteMenuItem, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.pasteMenuItem.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(pasteMenuItem, org.openide.util.NbBundle.getMessage(DropdownSingleKeywordSearchPanel.class, "DropdownSearchPanel.pasteMenuItem.text")); // NOI18N
rightClickMenu.add(pasteMenuItem);
org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.selectAllMenuItem.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(selectAllMenuItem, org.openide.util.NbBundle.getMessage(DropdownSingleKeywordSearchPanel.class, "DropdownSearchPanel.selectAllMenuItem.text")); // NOI18N
rightClickMenu.add(selectAllMenuItem);
keywordTextField.setFont(new java.awt.Font("Monospaced", 0, 14)); // NOI18N NON-NLS
keywordTextField.setText(org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.keywordTextField.text")); // NOI18N
keywordTextField.setFont(new java.awt.Font("Monospaced", 0, 14)); // NOI18N
keywordTextField.setText(org.openide.util.NbBundle.getMessage(DropdownSingleKeywordSearchPanel.class, "DropdownSearchPanel.keywordTextField.text")); // NOI18N
keywordTextField.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(192, 192, 192), 1, true));
keywordTextField.setMinimumSize(new java.awt.Dimension(2, 25));
keywordTextField.setPreferredSize(new java.awt.Dimension(2, 25));
@ -170,8 +194,8 @@ public class DropdownSingleTermSearchPanel extends KeywordSearchPanel {
}
});
searchButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/search-icon.png"))); // NOI18N NON-NLS
org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.searchButton.text")); // NOI18N
searchButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/keywordsearch/search-icon.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(DropdownSingleKeywordSearchPanel.class, "DropdownSearchPanel.searchButton.text")); // NOI18N
searchButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
searchButtonActionPerformed(evt);
@ -180,13 +204,13 @@ public class DropdownSingleTermSearchPanel extends KeywordSearchPanel {
queryTypeButtonGroup.add(exactRadioButton);
exactRadioButton.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(exactRadioButton, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.exactRadioButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(exactRadioButton, org.openide.util.NbBundle.getMessage(DropdownSingleKeywordSearchPanel.class, "DropdownSearchPanel.exactRadioButton.text")); // NOI18N
queryTypeButtonGroup.add(substringRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(substringRadioButton, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.substringRadioButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(substringRadioButton, org.openide.util.NbBundle.getMessage(DropdownSingleKeywordSearchPanel.class, "DropdownSearchPanel.substringRadioButton.text")); // NOI18N
queryTypeButtonGroup.add(regexRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(regexRadioButton, org.openide.util.NbBundle.getMessage(DropdownSingleTermSearchPanel.class, "DropdownSearchPanel.regexRadioButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(regexRadioButton, org.openide.util.NbBundle.getMessage(DropdownSingleKeywordSearchPanel.class, "DropdownSearchPanel.regexRadioButton.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
@ -224,18 +248,33 @@ public class DropdownSingleTermSearchPanel extends KeywordSearchPanel {
);
}// </editor-fold>//GEN-END:initComponents
/**
* Action performed by the action listener for the search button.
*
* @param evt The action event.
*/
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
keywordTextFieldActionPerformed(evt);
}//GEN-LAST:event_searchButtonActionPerformed
/**
* Action performed by the action listener for the keyword text field.
*
* @param evt The action event.
*/
private void keywordTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keywordTextFieldActionPerformed
try {
search();
} catch (Exception e) {
logger.log(Level.SEVERE, "search() threw exception", e); //NON-NLS
LOGGER.log(Level.SEVERE, "Error performing ad hoc single keyword search", e); //NON-NLS
}
}//GEN-LAST:event_keywordTextFieldActionPerformed
/**
* Mouse event handler for the keyword text field.
*
* @param evt The mouse event.
*/
private void keywordTextFieldMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_keywordTextFieldMouseClicked
if (evt.isPopupTrigger()) {
rightClickMenu.show(evt.getComponent(), evt.getX(), evt.getY());

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2003-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -16,11 +16,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* DropdownToolbar
*
*/
package org.sleuthkit.autopsy.keywordsearch;
import java.awt.event.ActionEvent;
@ -37,22 +32,26 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.core.RuntimeProperties;
/**
* Keyword search tool bar (in upper right, by default) with drop down panels
* for ad hoc searches by list or expression.
* A panel that provides a toolbar button for the dropdown keyword list search
* panel and dropdown single keyword search panel. Displayed in the upper right
* hand corner of the application by default.
*/
class DropdownToolbar extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(DropdownToolbar.class.getName());
private KeywordPropertyChangeListener listener;
private boolean active = false;
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(DropdownToolbar.class.getName());
private static DropdownToolbar instance;
private DropdownSingleTermSearchPanel dropPanel = null;
private DropdownToolbar() {
initComponents();
customizeComponents();
}
private SearchSettingsChangeListener searchSettingsChangeListener;
private boolean active = false;
private DropdownSingleKeywordSearchPanel dropPanel = null;
/**
* Gets the singleton panel that provides a toolbar button for the dropdown
* keyword list search panel and dropdown single keyword search panel.
* Displayed in the upper right hand corner of the application by default.
*
* @return The panel.
*/
public synchronized static DropdownToolbar getDefault() {
if (instance == null) {
instance = new DropdownToolbar();
@ -60,18 +59,30 @@ class DropdownToolbar extends javax.swing.JPanel {
return instance;
}
/**
* Constructs a panel that provides a toolbar button for the dropdown
* keyword list search panel and dropdown single keyword search panel.
* Displayed in the upper right hand corner of the application by default.
*/
private DropdownToolbar() {
initComponents();
customizeComponents();
}
/**
* Does additional initialization of the GUI components created by the
* initComponents method.
*/
private void customizeComponents() {
listener = new KeywordPropertyChangeListener();
KeywordSearch.getServer().addServerActionListener(listener);
Case.addPropertyChangeListener(listener);
searchSettingsChangeListener = new SearchSettingsChangeListener();
KeywordSearch.getServer().addServerActionListener(searchSettingsChangeListener);
Case.addPropertyChangeListener(searchSettingsChangeListener);
DropdownListSearchPanel listsPanel = DropdownListSearchPanel.getDefault();
listsPanel.addSearchButtonActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listsPanel.addSearchButtonActionListener((ActionEvent e) -> {
listsMenu.setVisible(false);
}
});
// Adding border of six to account for menu border
listsMenu.setSize(listsPanel.getPreferredSize().width + 6, listsPanel.getPreferredSize().height + 6);
listsMenu.add(listsPanel);
@ -92,7 +103,7 @@ class DropdownToolbar extends javax.swing.JPanel {
}
});
dropPanel = DropdownSingleTermSearchPanel.getDefault();
dropPanel = DropdownSingleKeywordSearchPanel.getDefault();
dropPanel.addSearchButtonActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@ -120,6 +131,27 @@ class DropdownToolbar extends javax.swing.JPanel {
}
private void maybeShowListsPopup(MouseEvent evt) {
if (!active) {
return;
}
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
return;
}
listsMenu.show(listsButton, listsButton.getWidth() - listsMenu.getWidth(), listsButton.getHeight() - 1);
}
private void maybeShowSearchPopup(MouseEvent evt) {
if (!active) {
return;
}
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
return;
}
searchMenu.show(searchDropButton, searchDropButton.getWidth() - searchMenu.getWidth(), searchDropButton.getHeight() - 1);
}
/**
* 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
@ -216,13 +248,13 @@ class DropdownToolbar extends javax.swing.JPanel {
private javax.swing.JPopupMenu searchMenu;
// End of variables declaration//GEN-END:variables
private class KeywordPropertyChangeListener implements PropertyChangeListener {
private class SearchSettingsChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String changed = evt.getPropertyName();
if (changed.equals(Case.Events.CURRENT_CASE.toString())) {
dropPanel.resetSearchBox();
dropPanel.clearSearchBox();
setFields(null != evt.getNewValue() && RuntimeProperties.coreComponentsAreActive());
} else if (changed.equals(Server.CORE_EVT)) {
final Server.CORE_EVT_STATES state = (Server.CORE_EVT_STATES) evt.getNewValue();
@ -232,9 +264,9 @@ class DropdownToolbar extends javax.swing.JPanel {
final int numIndexedFiles = KeywordSearch.getServer().queryNumIndexedFiles();
KeywordSearch.fireNumIndexedFilesChange(null, numIndexedFiles);
} catch (NoOpenCoreException ex) {
logger.log(Level.SEVERE, "Error executing Solr query, {0}", ex); //NON-NLS
LOGGER.log(Level.SEVERE, "Error executing Solr query, {0}", ex); //NON-NLS
} catch (KeywordSearchModuleException se) {
logger.log(Level.SEVERE, "Error executing Solr query, {0}", se.getMessage()); //NON-NLS
LOGGER.log(Level.SEVERE, "Error executing Solr query, {0}", se.getMessage()); //NON-NLS
}
break;
case STOPPED:
@ -251,23 +283,4 @@ class DropdownToolbar extends javax.swing.JPanel {
}
}
private void maybeShowListsPopup(MouseEvent evt) {
if (!active) {
return;
}
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
return;
}
listsMenu.show(listsButton, listsButton.getWidth() - listsMenu.getWidth(), listsButton.getHeight() - 1);
}
private void maybeShowSearchPopup(MouseEvent evt) {
if (!active) {
return;
}
if (evt != null && !SwingUtilities.isLeftMouseButton(evt)) {
return;
}
searchMenu.show(searchDropButton, searchDropButton.getWidth() - searchMenu.getWidth(), searchDropButton.getHeight() - 1);
}
}

View File

@ -100,7 +100,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
lsm.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (lsm.isSelectionEmpty() || currentKeywordList.isLocked() || IngestManager.getInstance().isIngestRunning()) {
if (lsm.isSelectionEmpty() || currentKeywordList.isEditable() || IngestManager.getInstance().isIngestRunning()) {
deleteWordButton.setEnabled(false);
} else {
deleteWordButton.setEnabled(true);
@ -140,7 +140,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
listOptionsSeparator.setEnabled(canEditList);
// items that need an unlocked list w/out ingest running
boolean isListLocked = ((isListSelected == false) || (currentKeywordList.isLocked()));
boolean isListLocked = ((isListSelected == false) || (currentKeywordList.isEditable()));
boolean canAddWord = isListSelected && !isIngestRunning && !isListLocked;
newWordButton.setEnabled(canAddWord);
keywordOptionsLabel.setEnabled(canAddWord);
@ -581,10 +581,10 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis
Keyword word = currentKeywordList.getKeywords().get(rowIndex);
switch (columnIndex) {
case 0:
ret = (Object) word.getQuery();
ret = (Object) word.getSearchTerm();
break;
case 1:
ret = (Object) !word.isLiteral();
ret = (Object) !word.searchTermIsLiteral();
break;
default:
logger.log(Level.SEVERE, "Invalid table column index: {0}", columnIndex); //NON-NLS

View File

@ -82,7 +82,7 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
}
XmlKeywordSearchList writer = XmlKeywordSearchList.getCurrent();
if (writer.listExists(listName) && writer.getList(listName).isLocked()) {
if (writer.listExists(listName) && writer.getList(listName).isEditable()) {
KeywordSearchUtil.displayDialog(FEATURE_NAME, NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.noOwDefaultMsg"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN);
return;
}

View File

@ -176,7 +176,7 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
}
boolean shouldAdd = false;
if (writer.listExists(listName)) {
if (writer.getList(listName).isLocked()) {
if (writer.getList(listName).isEditable()) {
boolean replace = KeywordSearchUtil.displayConfirmDialog(
NbBundle.getMessage(this.getClass(), "KeywordSearch.newKeywordListMsg"),
NbBundle.getMessage(this.getClass(), "KeywordSearchListsManagementPanel.newKeywordListDescription", listName),

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -59,7 +59,7 @@ class Ingester {
//for ingesting chunk as SolrInputDocument (non-content-streaming, by-pass tika)
//TODO use a streaming way to add content to /update handler
private static final int MAX_DOC_CHUNK_SIZE = 1024 * 1024;
private static final String docContentEncoding = "UTF-8"; //NON-NLS
private static final String ENCODING = "UTF-8"; //NON-NLS
private Ingester() {
}
@ -134,7 +134,7 @@ class Ingester {
//overwrite id with the chunk id
params.put(Server.Schema.ID.toString(),
Server.getChunkIdString(sourceContent.getId(), fec.getChunkId()));
Server.getChunkIdString(sourceContent.getId(), fec.getChunkNumber()));
ingest(bcs, params, size);
}
@ -298,7 +298,7 @@ class Ingester {
if (read != 0) {
String s = "";
try {
s = new String(docChunkContentBuf, 0, read, docContentEncoding);
s = new String(docChunkContentBuf, 0, read, ENCODING);
// Sanitize by replacing non-UTF-8 characters with caret '^' before adding to index
char[] chars = null;
for (int i = 0; i < s.length(); i++) {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,81 +18,136 @@
*/
package org.sleuthkit.autopsy.keywordsearch;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.BlackboardAttribute;
/**
* Representation of single keyword to search for
* A representation of a keyword for which to search. The search term for the
* keyword may be either a literal term, to be treated as either a whole word or
* a substring, or a regex.
*
* It is currently possible to optionally associate an artifact attribute type
* with a keyword. This feature was added to support an initial implementation
* of account number search and may be removed in the future.
*/
class Keyword {
private String keywordString; // keyword to search for
private boolean isLiteral; // false if reg exp
private boolean isWholeword; // false if match a substring
private BlackboardAttribute.ATTRIBUTE_TYPE keywordType = null;
private String searchTerm;
private boolean isLiteral;
private boolean isWholeWord;
private BlackboardAttribute.ATTRIBUTE_TYPE artifactAtrributeType;
/**
* Constructs a representation of a keyword for which to search. The search
* term for the keyword may be either a literal term that will be treated as
* a whole word, or a regex.
*
* @param query Keyword to search for
* @param isLiteral false if reg exp
* @param searchTerm The search term for the keyword.
* @param isLiteral Whether or not the search term is a literal term that
* will be treated as a whole word, instead of a regex.
*/
Keyword(String query, boolean isLiteral) {
this.keywordString = query;
Keyword(String searchTerm, boolean isLiteral) {
this.searchTerm = searchTerm;
this.isLiteral = isLiteral;
this.isWholeword = true;
this.isWholeWord = true;
}
/**
* Constructs a representation of a keyword for which to search. The search
* term may be either a literal term, to be treated as either a whole word
* or as a substring, or a regex.
*
* @param query Keyword to search for
* @param isLiteral false if reg exp
* @param isWholeword false to match substring (undefined behavior if regexp
* is true)
* @param searchTerm The search term.
* @param isLiteral Whether or not the search term is a literal term,
* instead of a regex.
* @param isWholeWord Whether or not the search term, if it is a literal
* search term, should be treated as a whole word rather
* than a substring.
*/
Keyword(String query, boolean isLiteral, boolean isWholeword) {
this.keywordString = query;
Keyword(String searchTerm, boolean isLiteral, boolean isWholeWord) {
this.searchTerm = searchTerm;
this.isLiteral = isLiteral;
this.isWholeword = isWholeword;
this.isWholeWord = isWholeWord;
}
/**
* Constructs a representation of a keyword for which to search, for the
* purpose of finding a specific artifact attribute. The search term may be
* either a literal term, to be treated as a whole word, or a regex.
*
* @param query Keyword to search for
* @param isLiteral false if reg exp
* @param keywordType
* The association of an artifact attribute type with a keyword was added to
* support an initial implementation of account number search and may be
* removed in the future.
*
* @param searchTerm The search term.
* @param isLiteral Whether or not the search term is a literal term, to
* be treated as a whole word, instead of a regex.
* @param keywordType The artifact attribute type.
*/
Keyword(String query, boolean isLiteral, BlackboardAttribute.ATTRIBUTE_TYPE keywordType) {
this(query, isLiteral);
this.keywordType = keywordType;
}
void setType(BlackboardAttribute.ATTRIBUTE_TYPE keywordType) {
this.keywordType = keywordType;
}
BlackboardAttribute.ATTRIBUTE_TYPE getType() {
return this.keywordType;
Keyword(String searchTerm, boolean isLiteral, BlackboardAttribute.ATTRIBUTE_TYPE artifactAtrributeType) {
this(searchTerm, isLiteral);
this.artifactAtrributeType = artifactAtrributeType;
}
/**
* Gets the search term for the keyword, which may be either a literal term
* or a regex.
*
* @return Keyword to search for
* @return The search term.
*/
String getQuery() {
return keywordString;
String getSearchTerm() {
return searchTerm;
}
boolean isLiteral() {
/**
* Indicates whether the search term for the keyword is a literal term or a
* regex.
*
* @return True or false.
*/
boolean searchTermIsLiteral() {
return isLiteral;
}
boolean isWholeword() {
return isWholeword;
/**
* Indicates whether or not the search term for the keyword, if it is a
* literal term and not a regex, will be treated as a whole word or as a
* substring.
*
* @return True or false.
*/
boolean searchTermIsWholeWord() {
return isWholeWord;
}
/**
* Sets the artifact attribute type associated with the keyword, if any.
*
* The association of an artifact attribute type with the keyword was added
* to support an initial implementation of account number search and may be
* removed in the future.
*
* @param artifactAtrributeType
*/
void setArtifactAttributeType(BlackboardAttribute.ATTRIBUTE_TYPE artifactAtrributeType) {
this.artifactAtrributeType = artifactAtrributeType;
}
/**
* Gets the artifact attribute type associated with the keyword, if any.
*
* The association of an artifact attribute type with the keyword was added
* to support an initial implementation of account number search and may be
* removed in the future.
*
* @return A attribute type object or null.
*/
BlackboardAttribute.ATTRIBUTE_TYPE getArtifactAttributeType() {
return this.artifactAtrributeType;
}
@Override
public String toString() {
return NbBundle.getMessage(this.getClass(), "Keyword.toString.text", keywordString, isLiteral, keywordType);
return String.format("Keyword{searchTerm='%s', isLiteral=%s, isWholeWord=%s}", searchTerm, isLiteral, isWholeWord);
}
@Override
@ -103,21 +158,19 @@ class Keyword {
if (getClass() != obj.getClass()) {
return false;
}
final Keyword other = (Keyword) obj;
if ((this.keywordString == null) ? (other.keywordString != null) : !this.keywordString.equals(other.keywordString)) {
return false;
}
if (this.isLiteral != other.isLiteral) {
return false;
}
return true;
Keyword other = (Keyword) obj;
return (this.searchTerm.equals(other.searchTerm)
&& this.isLiteral == other.isLiteral
&& this.isWholeWord == other.isWholeWord);
}
@Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + (this.keywordString != null ? this.keywordString.hashCode() : 0);
hash = 17 * hash + this.searchTerm.hashCode();
hash = 17 * hash + (this.isLiteral ? 1 : 0);
hash = 17 * hash + (this.isWholeWord ? 1 : 0);
return hash;
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,32 +21,75 @@ package org.sleuthkit.autopsy.keywordsearch;
import java.util.Date;
import java.util.List;
/**
* A list of keywords for which to search. Includes list creation and
* modification metadata and settings that determine how the list is to be used
* when ingesting a data source. Standard lists provided by Autopsy may be
* marked as not editable.
*/
public class KeywordList {
private String name;
private Date created;
private Date modified;
private Boolean useForIngest;
private Boolean ingestMessages;
private Boolean postIngestMessages;
private List<Keyword> keywords;
private Boolean locked;
private Boolean isEditable;
KeywordList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords, boolean locked) {
/**
* Constructs a list of keywords for which to search. Includes list creation
* and modification metadata and settings that determine how the list is to
* be used when ingesting a data source. Standard lists provided by Autopsy
* may be marked as not editable.
*
* @param name The name to asociate with the list.
* @param created When the list was created.
* @param modified When the list was last modified.
* @param useForIngest Whether or not the list is to be used when
* ingesting a data source.
* @param postIngestMessages Whether or not to post ingest inbox messages
* when a keyword within the list is found while
* ingesting a data source.
* @param keywords The keywords that make up the list.
* @param isEditable Whether or not the list may be edited by a
* user; standard lists provided by Autopsy should
* not be edited.
*/
KeywordList(String name, Date created, Date modified, Boolean useForIngest, Boolean postIngestMessages, List<Keyword> keywords, boolean isEditable) {
this.name = name;
this.created = created;
this.modified = modified;
this.useForIngest = useForIngest;
this.ingestMessages = ingestMessages;
this.postIngestMessages = postIngestMessages;
this.keywords = keywords;
this.locked = locked;
this.isEditable = isEditable;
}
/**
* Constructs a list of keywords for which to search. Includes list creation
* and modification metadata and settings that determine how the list is to
* be used when ingesting a data source. The list will be marked as a
* standard lists provided by Autopsy that should not be treated as
* editable.
*
* @param name The name to asociate with the list.
* @param created When the list was created.
* @param modified When the list was last modified.
* @param useForIngest Whether or not the list is to be used when
* ingesting a data source.
* @param postIngestMessages Whether or not to post ingest inbox messages
* when a keyword within the list is found while
* ingesting a data source.
* @param keywords The keywords that make up the list.
*/
KeywordList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords) {
this(name, created, modified, useForIngest, ingestMessages, keywords, false);
}
/**
* Create an unnamed list. Usually used for ad-hoc searches
* Constructs a temporary list of keywords to be used for ad hoc keyword
* search and then discarded.
*
* @param keywords
*/
@ -54,74 +97,116 @@ public class KeywordList {
this("", new Date(0), new Date(0), false, false, keywords, false);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final KeywordList other = (KeywordList) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 5;
return hash;
}
/**
* Get the name assigned to the keyword list.
*
* @return The list name.
*/
String getName() {
return name;
}
/**
* Gets the date the keyword list was created.
*
* @return The date.
*/
Date getDateCreated() {
return created;
}
/**
* Gets the date the keyword list was last modified.
*
* @return The date.
*/
Date getDateModified() {
return modified;
}
/**
* Gets whether or not the list should be used when ingesting a data source.
*
* @return True or false.
*/
Boolean getUseForIngest() {
return useForIngest;
}
void setUseForIngest(boolean use) {
this.useForIngest = use;
/**
* Sets whether or not the list should be used when ingesting a data source.
*
* @param useForIngest True or false.
*/
void setUseForIngest(boolean useForIngest) {
this.useForIngest = useForIngest;
}
/**
* Gets whether or not to post ingest inbox messages when a keyword within
* the list is found while ingesting a data source.
*
* @return true or false
*/
Boolean getIngestMessages() {
return ingestMessages;
return postIngestMessages;
}
void setIngestMessages(boolean ingestMessages) {
this.ingestMessages = ingestMessages;
/**
* Sets whether or not to post ingest inbox messages when a keyword within
* the list is found while ingesting a data source.
*
* @param postIngestMessages True or false.
*/
void setIngestMessages(boolean postIngestMessages) {
this.postIngestMessages = postIngestMessages;
}
/**
* Gets the keywords included in the list
*
* @return A colleciton of Keyword objects.
*/
List<Keyword> getKeywords() {
return keywords;
}
/**
* Indicates whether or not a given keyword is included in the list.
*
* @param keyword The keyword of interest.
*
* @return
*/
boolean hasKeyword(Keyword keyword) {
return keywords.contains(keyword);
}
boolean hasKeyword(String keyword) {
//note, this ignores isLiteral
for (Keyword k : keywords) {
if (k.getQuery().equals(keyword)) {
/**
* Indicates whether or not a given search term is included in the list.
*
* @param searchTerm The search term.
*
* @return True or false.
*/
boolean hasSearchTerm(String searchTerm) {
for (Keyword word : keywords) {
if (word.getSearchTerm().equals(searchTerm)) {
return true;
}
}
return false;
}
Boolean isLocked() {
return locked;
/**
* Indicates Whether or not the list should be editable by a user; standard
* lists provided by Autopsy should be marked as not editable when they are
* contructed.
*
* @return True or false.
*/
Boolean isEditable() {
return isEditable;
}
}

View File

@ -124,7 +124,7 @@ abstract class KeywordSearchList {
List<Keyword> ccns = new ArrayList<>();
ccns.add(new Keyword(CCN_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
lockedLists.add("Credit Card Numbers");
addList("Credit Card Numbers", ccns, true, false, true);
addList("Credit Card Numbers", ccns, false, false, true);
}
/**
@ -141,7 +141,7 @@ abstract class KeywordSearchList {
//we want to preserve state of locked lists
List<String> toClear = new ArrayList<>();
for (String list : theLists.keySet()) {
if (theLists.get(list).isLocked() == false) {
if (theLists.get(list).isEditable() == false) {
toClear.add(list);
}
}
@ -173,7 +173,7 @@ abstract class KeywordSearchList {
public List<KeywordList> getListsL(boolean locked) {
List<KeywordList> ret = new ArrayList<>();
for (KeywordList list : theLists.values()) {
if (list.isLocked().equals(locked)) {
if (list.isEditable().equals(locked)) {
ret.add(list);
}
}
@ -200,7 +200,7 @@ abstract class KeywordSearchList {
ArrayList<String> lists = new ArrayList<>();
for (String listName : theLists.keySet()) {
KeywordList list = theLists.get(listName);
if (locked == list.isLocked()) {
if (locked == list.isEditable()) {
lists.add(listName);
}
}
@ -218,7 +218,7 @@ abstract class KeywordSearchList {
public KeywordList getListWithKeyword(String keyword) {
KeywordList found = null;
for (KeywordList list : theLists.values()) {
if (list.hasKeyword(keyword)) {
if (list.hasSearchTerm(keyword)) {
found = list;
break;
}
@ -246,7 +246,7 @@ abstract class KeywordSearchList {
int numLists = 0;
for (String listName : theLists.keySet()) {
KeywordList list = theLists.get(listName);
if (locked == list.isLocked()) {
if (locked == list.isEditable()) {
++numLists;
}
}
@ -330,7 +330,7 @@ abstract class KeywordSearchList {
}
boolean addList(KeywordList list) {
return addList(list.getName(), list.getKeywords(), list.getUseForIngest(), list.getIngestMessages(), list.isLocked());
return addList(list.getName(), list.getKeywords(), list.getUseForIngest(), list.getIngestMessages(), list.isEditable());
}
/**
@ -437,7 +437,7 @@ abstract class KeywordSearchList {
*/
boolean deleteList(String name) {
KeywordList delList = getList(name);
if (delList != null && !delList.isLocked()) {
if (delList != null && !delList.isEditable()) {
theLists.remove(name);
}

View File

@ -39,7 +39,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
@ServiceProvider(service = IngestModuleFactory.class)
public class KeywordSearchModuleFactory extends IngestModuleFactoryAdapter {
private static final HashSet<String> defaultDisabledKeywordListNames = new HashSet<>(Arrays.asList("Phone Numbers", "IP Addresses", "URLs")); //NON-NLS
private static final HashSet<String> defaultDisabledKeywordListNames = new HashSet<>(Arrays.asList("Phone Numbers", "IP Addresses", "URLs", "Credit Card Numbers")); //NON-NLS
private KeywordSearchJobSettingsPanel jobSettingsPanel = null;
@Override

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,11 +18,8 @@
*/
package org.sleuthkit.autopsy.keywordsearch;
import org.sleuthkit.datamodel.AbstractFile;
/**
* Interface for a search query. Implemented by various engines or methods of
* using the same engine. One of these is created for each query.
* Interface for kewyord search queries.
*/
interface KeywordSearchQuery {
@ -33,7 +30,7 @@ interface KeywordSearchQuery {
*
* @return true if the query passed validation
*/
public boolean validate();
boolean validate();
/**
* execute query and return results without publishing them return results
@ -43,7 +40,7 @@ interface KeywordSearchQuery {
* could be a notification to stop processing
* @return
*/
public QueryResults performQuery() throws NoOpenCoreException;
QueryResults performQuery() throws NoOpenCoreException;
/**
* Set an optional filter to narrow down the search Adding multiple filters
@ -51,14 +48,14 @@ interface KeywordSearchQuery {
*
* @param filter filter to set on the query
*/
public void addFilter(KeywordQueryFilter filter);
void addFilter(KeywordQueryFilter filter);
/**
* Set an optional SOLR field to narrow down the search
*
* @param field field to set on the query
*/
public void setField(String field);
void setField(String field);
/**
* Modify the query string to be searched as a substring instead of a whole
@ -66,39 +63,39 @@ interface KeywordSearchQuery {
*
* @param isSubstring
*/
public void setSubstringQuery();
void setSubstringQuery();
/**
* escape the query string and use the escaped string in the query
*/
public void escape();
void escape();
/**
*
* @return true if query was escaped
*/
public boolean isEscaped();
boolean isEscaped();
/**
*
* @return true if query is a literal query (non regex)
*/
public boolean isLiteral();
boolean isLiteral();
/**
* return original keyword/query string
*
* @return the query String supplied originally
*/
public String getQueryString();
String getQueryString();
/**
* return escaped keyword/query string if escaping was done
*
* @return the escaped query string, or original string if no escaping done
*/
public String getEscapedQueryString();
String getEscapedQueryString();
public KeywordCachedArtifact writeSingleFileHitsToBlackBoard(String termHit, KeywordHit hit, String snippet, String listName);
KeywordCachedArtifact writeSingleFileHitsToBlackBoard(String termHit, KeywordHit hit, String snippet, String listName);
}

View File

@ -29,6 +29,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
@ -55,20 +56,20 @@ class KeywordSearchQueryDelegator {
for (KeywordList keywordList : keywordLists) {
for (Keyword keyword : keywordList.getKeywords()) {
KeywordSearchQuery query;
if (keyword.isLiteral()) {
if (keyword.searchTermIsLiteral()) {
// literal, exact match
if (keyword.isWholeword()) {
if (keyword.searchTermIsWholeWord()) {
query = new LuceneQuery(keywordList, keyword);
query.escape();
} // literal, substring match
else {
query = new TermComponentQuery(keywordList, keyword);
query = new TermsComponentQuery(keywordList, keyword);
query.escape();
query.setSubstringQuery();
}
} // regexp
else {
query = new TermComponentQuery(keywordList, keyword);
query = new TermsComponentQuery(keywordList, keyword);
}
queryDelegates.add(query);
}
@ -108,7 +109,8 @@ class KeywordSearchQueryDelegator {
final String pathText = NbBundle.getMessage(this.getClass(), "KeywordSearchQueryManager.pathText.text");
DataResultTopComponent.initInstance(pathText, rootNode, queryRequests.size(), searchResultWin);
DataResultTopComponent.initInstance(pathText, new TableFilterNode(rootNode, true, KeywordSearch.class.getName()),
queryRequests.size(), searchResultWin);
searchResultWin.requestActive();
}

View File

@ -255,8 +255,8 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
//the query is executed later on demand
if (queryResults.getKeywords().size() == 1) {
//simple case, no need to process subqueries and do special escaping
Keyword term = queryResults.getKeywords().iterator().next();
return constructEscapedSolrQuery(term.getQuery(), literal_query);
Keyword keyword = queryResults.getKeywords().iterator().next();
return constructEscapedSolrQuery(keyword.getSearchTerm(), literal_query);
} else {
//find terms for this content hit
List<Keyword> hitTerms = new ArrayList<>();
@ -274,7 +274,7 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
int curTerm = 0;
for (Keyword term : hitTerms) {
//escape subqueries, MAKE SURE they are not escaped again later
highlightQuery.append(constructEscapedSolrQuery(term.getQuery(), literal_query));
highlightQuery.append(constructEscapedSolrQuery(term.getSearchTerm(), literal_query));
if (lastTerm != curTerm) {
highlightQuery.append(" "); //acts as OR ||
}

View File

@ -55,7 +55,7 @@ class LuceneQuery implements KeywordSearchQuery {
private final String keywordString; //original unescaped query
private String keywordStringEscaped;
private boolean isEscaped;
private Keyword keywordQuery = null;
private Keyword keyword = null;
private KeywordList keywordList = null;
private final List<KeywordQueryFilter> filters = new ArrayList<>();
private String field = null;
@ -72,15 +72,15 @@ class LuceneQuery implements KeywordSearchQuery {
/**
* Constructor with query to process.
*
* @param keywordQuery
* @param keyword
*/
public LuceneQuery(KeywordList keywordList, Keyword keywordQuery) {
public LuceneQuery(KeywordList keywordList, Keyword keyword) {
this.keywordList = keywordList;
this.keywordQuery = keywordQuery;
this.keyword = keyword;
// @@@ BC: Long-term, we should try to get rid of this string and use only the
// keyword object. Refactoring did not make its way through this yet.
this.keywordString = keywordQuery.getQuery();
this.keywordString = keyword.getSearchTerm();
this.keywordStringEscaped = this.keywordString;
}
@ -168,8 +168,8 @@ class LuceneQuery implements KeywordSearchQuery {
//bogus - workaround the dir tree table issue
//attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID(), MODULE_NAME, "", ""));
//selector
if (keywordQuery != null) {
BlackboardAttribute.ATTRIBUTE_TYPE selType = keywordQuery.getType();
if (keyword != null) {
BlackboardAttribute.ATTRIBUTE_TYPE selType = keyword.getArtifactAttributeType();
if (selType != null) {
attributes.add(new BlackboardAttribute(selType, MODULE_NAME, termHit));
}

View File

@ -115,7 +115,7 @@ class QueryResults {
for (final Keyword keyword : getKeywords()) {
if (worker.isCancelled()) {
logger.log(Level.INFO, "Cancel detected, bailing before new keyword processed: {0}", keyword.getQuery()); //NON-NLS
logger.log(Level.INFO, "Cancel detected, bailing before new keyword processed: {0}", keyword.getSearchTerm()); //NON-NLS
break;
}
@ -124,7 +124,7 @@ class QueryResults {
progress.progress(keyword.toString(), unitProgress);
}
if (subProgress != null) {
String hitDisplayStr = keyword.getQuery();
String hitDisplayStr = keyword.getSearchTerm();
if (hitDisplayStr.length() > 50) {
hitDisplayStr = hitDisplayStr.substring(0, 49) + "...";
}
@ -132,7 +132,7 @@ class QueryResults {
}
for (KeywordHit hit : getOneHitPerObject(keyword)) {
String termString = keyword.getQuery();
String termString = keyword.getSearchTerm();
final String snippetQuery = KeywordSearchUtil.escapeLuceneQuery(termString);
String snippet;
try {
@ -250,11 +250,12 @@ class QueryResults {
//list
attr = written.getAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
if (attr != null) {
detailsSb.append("<tr>"); //NON-NLS
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.listThLbl"));
detailsSb.append("<td>").append(attr.getValueString()).append("</td>"); //NON-NLS
detailsSb.append("</tr>"); //NON-NLS
}
//regex
if (!keywordSearchQuery.isLiteral()) {
attr = written.getAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID());

View File

@ -403,7 +403,7 @@ public final class SearchRunner {
ProgressContributor[] subProgresses = new ProgressContributor[keywords.size()];
int i = 0;
for (Keyword keywordQuery : keywords) {
subProgresses[i] = AggregateProgressFactory.createProgressContributor(keywordQuery.getQuery());
subProgresses[i] = AggregateProgressFactory.createProgressContributor(keywordQuery.getSearchTerm());
progressGroup.addContributor(subProgresses[i]);
i++;
}
@ -419,11 +419,11 @@ public final class SearchRunner {
for (Keyword keywordQuery : keywords) {
if (this.isCancelled()) {
logger.log(Level.INFO, "Cancel detected, bailing before new keyword processed: {0}", keywordQuery.getQuery()); //NON-NLS
logger.log(Level.INFO, "Cancel detected, bailing before new keyword processed: {0}", keywordQuery.getSearchTerm()); //NON-NLS
return null;
}
final String queryStr = keywordQuery.getQuery();
final String queryStr = keywordQuery.getSearchTerm();
final KeywordList list = keywordToList.get(queryStr);
//new subProgress will be active after the initial query
@ -434,9 +434,9 @@ public final class SearchRunner {
KeywordSearchQuery keywordSearchQuery = null;
boolean isRegex = !keywordQuery.isLiteral();
boolean isRegex = !keywordQuery.searchTermIsLiteral();
if (isRegex) {
keywordSearchQuery = new TermComponentQuery(list, keywordQuery);
keywordSearchQuery = new TermsComponentQuery(list, keywordQuery);
} else {
keywordSearchQuery = new LuceneQuery(list, keywordQuery);
keywordSearchQuery.escape();
@ -454,16 +454,16 @@ public final class SearchRunner {
try {
queryResults = keywordSearchQuery.performQuery();
} catch (NoOpenCoreException ex) {
logger.log(Level.WARNING, "Error performing query: " + keywordQuery.getQuery(), ex); //NON-NLS
logger.log(Level.WARNING, "Error performing query: " + keywordQuery.getSearchTerm(), ex); //NON-NLS
//no reason to continue with next query if recovery failed
//or wait for recovery to kick in and run again later
//likely case has closed and threads are being interrupted
return null;
} catch (CancellationException e) {
logger.log(Level.INFO, "Cancel detected, bailing during keyword query: {0}", keywordQuery.getQuery()); //NON-NLS
logger.log(Level.INFO, "Cancel detected, bailing during keyword query: {0}", keywordQuery.getSearchTerm()); //NON-NLS
return null;
} catch (Exception e) {
logger.log(Level.WARNING, "Error performing query: " + keywordQuery.getQuery(), e); //NON-NLS
logger.log(Level.WARNING, "Error performing query: " + keywordQuery.getSearchTerm(), e); //NON-NLS
continue;
}
@ -481,7 +481,7 @@ public final class SearchRunner {
int totalUnits = newResults.getKeywords().size();
subProgresses[keywordsSearched].start(totalUnits);
int unitProgress = 0;
String queryDisplayStr = keywordQuery.getQuery();
String queryDisplayStr = keywordQuery.getSearchTerm();
if (queryDisplayStr.length() > 50) {
queryDisplayStr = queryDisplayStr.substring(0, 49) + "...";
}
@ -547,7 +547,7 @@ public final class SearchRunner {
keywordLists.add(list);
for (Keyword k : list.getKeywords()) {
keywords.add(k);
keywordToList.put(k.getQuery(), list);
keywordToList.put(k.getSearchTerm(), list);
}
}
}

View File

@ -1,433 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 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 com.google.common.base.CharMatcher;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.validator.routines.checkdigit.LuhnCheckDigit;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.TermsResponse.Term;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.datamodel.CreditCards;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Performs a regular expression query to the SOLR/Lucene instance.
*/
final class TermComponentQuery implements KeywordSearchQuery {
private static final Logger LOGGER = Logger.getLogger(TermComponentQuery.class.getName());
private static final boolean DEBUG = Version.Type.DEVELOPMENT.equals(Version.getBuildType());
private static final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
private static final BlackboardAttribute.Type KEYWORD_SEARCH_DOCUMENT_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID);
//TODO: move these regex and the luhn check to a new class, something like: CreditCardNumberValidator
/*
* Track 2 is numeric plus six punctuation symbolls :;<=>?
*
* This regex matches 12-19 digit ccns embeded in a track 2 formated string.
* This regex matches (and extracts groups) even if the entire track is not
* present as long as the part that is conforms to the track format.
*
*/
private static final Pattern TRACK2_PATTERN = Pattern.compile(
"[:;<=>?]?" //(optional)start sentinel //NON-NLS
+ "(?<accountNumber>[3456]([ -]?\\d){11,18})" //12-19 digits, with possible single spaces or dashes in between. first digit is 3,4,5, or 6 //NON-NLS
+ "(?:[:;<=>?]" //separator //NON-NLS
+ "(?:(?<expiration>\\d{4})" //4 digit expiration date YYMM //NON-NLS
+ "(?:(?<serviceCode>\\d{3})" //3 digit service code //NON-NLS
+ "(?:(?<discretionary>[^:;<=>?]*)" //discretionary data, not containing punctuation marks //NON-NLS
+ "(?:[:;<=>?]" //end sentinel //NON-NLS
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
+ "?)?)?)?)?)?"); //close nested optional groups //NON-NLS
/*
* Track 1 is alphanumeric.
*
* This regex matches 12-19 digit ccns embeded in a track 1 formated string.
* This regex matches (and extracts groups) even if the entire track is not
* present as long as the part that is conforms to the track format.
*/
private static final Pattern TRACK1_PATTERN = Pattern.compile(
"(?:" //begin nested optinal group //NON-NLS
+ "%?" //optional start sentinal: % //NON-NLS
+ "B)?" //format code //NON-NLS
+ "(?<accountNumber>[3456]([ -]?\\d){11,18})" //12-19 digits, with possible single spaces or dashes in between. first digit is 3,4,5, or 6 //NON-NLS
+ "\\^" //separator //NON-NLS
+ "(?<name>[^^]{2,26})" //2-26 charachter name, not containing ^ //NON-NLS
+ "(?:\\^" //separator //NON-NLS
+ "(?:(?:\\^|(?<expiration>\\d{4}))" //separator or 4 digit expiration YYMM //NON-NLS
+ "(?:(?:\\^|(?<serviceCode>\\d{3}))"//separator or 3 digit service code //NON-NLS
+ "(?:(?<discretionary>[^?]*)" // discretionary data not containing separator //NON-NLS
+ "(?:\\?" // end sentinal: ? //NON-NLS
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
+ "?)?)?)?)?)?");//close nested optional groups //NON-NLS
private static final Pattern CCN_PATTERN = Pattern.compile("(?<ccn>[3456]([ -]?\\d){11,18})"); //12-19 digits, with possible single spaces or dashes in between. first digit is 3,4,5, or 6 //NON-NLS
private static final LuhnCheckDigit LUHN_CHECK = new LuhnCheckDigit();
//corresponds to field in Solr schema, analyzed with white-space tokenizer only
private static final String TERMS_SEARCH_FIELD = Server.Schema.CONTENT_WS.toString();
private static final String TERMS_HANDLER = "/terms"; //NON-NLS
private static final int TERMS_TIMEOUT = 90 * 1000; //in ms
private static final String CASE_INSENSITIVE = "case_insensitive"; //NON-NLS
private static final int MAX_TERMS_RESULTS = 20000;
private String escapedQuery;
private final KeywordList keywordList;
private final Keyword keyword;
private boolean isEscaped;
private final List<KeywordQueryFilter> filters = new ArrayList<>();
TermComponentQuery(KeywordList keywordList, Keyword keyword) {
this.keyword = keyword;
this.keywordList = keywordList;
this.escapedQuery = keyword.getQuery();
}
@Override
public void addFilter(KeywordQueryFilter filter) {
this.filters.add(filter);
}
/**
* @param field
*
* @deprecated This method is unused and no-op
*/
@Override
@Deprecated
public void setField(String field) {
}
@Override
public void setSubstringQuery() {
escapedQuery = ".*" + escapedQuery + ".*";
}
@Override
public void escape() {
escapedQuery = Pattern.quote(keyword.getQuery());
isEscaped = true;
}
@Override
public boolean validate() {
if (escapedQuery.isEmpty()) {
return false;
}
try {
Pattern.compile(escapedQuery);
return true;
} catch (IllegalArgumentException ex) {
return false;
}
}
@Override
public boolean isEscaped() {
return isEscaped;
}
@Override
public boolean isLiteral() {
return false;
}
@Override
public String getEscapedQueryString() {
return this.escapedQuery;
}
@Override
public String getQueryString() {
return keyword.getQuery();
}
@Override
public KeywordCachedArtifact writeSingleFileHitsToBlackBoard(String termHit, KeywordHit hit, String snippet, String listName) {
BlackboardArtifact newArtifact;
Collection<BlackboardAttribute> attributes = new ArrayList<>();
if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name()));
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
//try to match it against the track 1 regex
Matcher matcher = TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
//then try to match it against the track 2 regex
matcher = TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
//if we couldn't parse the CCN abort this artifact
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
LOGGER.log(Level.SEVERE, "Failed to parse CCN from hit: " + hit.getSnippet());
return null;
}
attributes.addAll(parsedTrackAttributeMap.values());
//look up the bank name, schem, etc from the BIN
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/* if the hit is from unused or unalocated blocks, record the
* KEYWORD_SEARCH_DOCUMENT_ID, so we can show just that chunk in the
* UI
*/
if (hit.getContent() instanceof AbstractFile) {
AbstractFile file = (AbstractFile) hit.getContent();
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
// make account artifact
try {
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
} catch (TskCoreException tskCoreException) {
LOGGER.log(Level.SEVERE, "Error adding bb artifact for account", tskCoreException); //NON-NLS
return null;
}
} else {
//regex match
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, termHit));
//regex keyword
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, keyword.getQuery()));
if (StringUtils.isNotEmpty(listName)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
}
//make keyword hit artifact
try {
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
} catch (TskCoreException tskCoreException) {
LOGGER.log(Level.SEVERE, "Error adding bb artifact for keyword hit", tskCoreException); //NON-NLS
return null;
}
}
//preview
if (snippet != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet));
}
if (hit.isArtifactHit()) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, hit.getArtifact().getArtifactID()));
}
try {
//TODO: do we still/really need this KeywordCachedArtifact class?
newArtifact.addAttributes(attributes);
KeywordCachedArtifact writeResult = new KeywordCachedArtifact(newArtifact);
writeResult.add(attributes);
return writeResult;
} catch (TskCoreException e) {
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
return null;
}
}
@Override
public QueryResults performQuery() throws NoOpenCoreException {
/*
* Execute the regex query to get a list of terms that match the regex.
* Note that the field that is being searched is tokenized based on
* whitespace.
*/
//create the query
final SolrQuery q = new SolrQuery();
q.setRequestHandler(TERMS_HANDLER);
q.setTerms(true);
q.setTermsRegexFlag(CASE_INSENSITIVE);
q.setTermsRegex(escapedQuery);
q.addTermsField(TERMS_SEARCH_FIELD);
q.setTimeAllowed(TERMS_TIMEOUT);
q.setShowDebugInfo(DEBUG);
q.setTermsLimit(MAX_TERMS_RESULTS);
LOGGER.log(Level.INFO, "Query: {0}", q.toString()); //NON-NLS
//execute the query
List<Term> terms = null;
try {
terms = KeywordSearch.getServer().queryTerms(q).getTerms(TERMS_SEARCH_FIELD);
} catch (KeywordSearchModuleException ex) {
LOGGER.log(Level.SEVERE, "Error executing the regex terms query: " + keyword.getQuery(), ex); //NON-NLS
//TODO: this is almost certainly wrong and guaranteed to throw a NPE at some point!!!!
}
/*
* For each term that matched the regex, query for full set of document
* hits for that term.
*/
QueryResults results = new QueryResults(this, keywordList);
int resultSize = 0;
for (Term term : terms) {
final String termStr = KeywordSearchUtil.escapeLuceneQuery(term.getTerm());
if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
//If the keyword is a credit card number, pass it through luhn validator
Matcher matcher = CCN_PATTERN.matcher(term.getTerm());
matcher.find();
final String ccn = CharMatcher.anyOf(" -").removeFrom(matcher.group("ccn"));
if (false == LUHN_CHECK.isValid(ccn)) {
continue; //if the hit does not pass the luhn check, skip it.
}
}
/*
* Note: we can't set filter query on terms query but setting filter
* query on fileResults query will yield the same result
*/
LuceneQuery filesQuery = new LuceneQuery(keywordList, new Keyword(termStr, true));
filters.forEach(filesQuery::addFilter);
try {
QueryResults fileQueryResults = filesQuery.performQuery();
Set<KeywordHit> filesResults = new HashSet<>();
for (Keyword key : fileQueryResults.getKeywords()) { //flatten results into a single list
List<KeywordHit> keyRes = fileQueryResults.getResults(key);
resultSize += keyRes.size();
filesResults.addAll(keyRes);
}
results.addResult(new Keyword(term.getTerm(), false), new ArrayList<>(filesResults));
} catch (NoOpenCoreException | RuntimeException e) {
LOGGER.log(Level.WARNING, "Error executing Solr query,", e); //NON-NLS
throw e;
}
}
//TODO limit how many results we store, not to hit memory limits
LOGGER.log(Level.INFO, "Regex # results: {0}", resultSize); //NON-NLS
return results;
}
@Override
public KeywordList getKeywordList() {
return keywordList;
}
/**
* Add an attribute of the the given type to the given artifact with the
* value taken from the matcher. If an attribute of the given type already
* exists on the artifact or if the value is null, no attribute is added.
*
* @param attributeMap
* @param attrType
* @param groupName
* @param matcher *
*/
static private void addAttributeIfNotAlreadyCaptured(Map<BlackboardAttribute.Type, BlackboardAttribute> attributeMap, ATTRIBUTE_TYPE attrType, String groupName, Matcher matcher) {
BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrType);
attributeMap.computeIfAbsent(type, (BlackboardAttribute.Type t) -> {
String value = matcher.group(groupName);
if (attrType.equals(ATTRIBUTE_TYPE.TSK_CARD_NUMBER)) {
value = CharMatcher.anyOf(" -").removeFrom(value);
}
if (StringUtils.isNotBlank(value)) {
return new BlackboardAttribute(attrType, MODULE_NAME, value);
}
return null;
});
}
/**
* Parse the track 2 data from a KeywordHit and add it to the given
* artifact.
*
* @param attributeMAp
* @param matcher
*/
static private void parseTrack2Data(Map<BlackboardAttribute.Type, BlackboardAttribute> attributeMAp, Matcher matcher) {
//try to add all the attrributes common to track 1 and 2
addAttributeIfNotAlreadyCaptured(attributeMAp, ATTRIBUTE_TYPE.TSK_CARD_NUMBER, "accountNumber", matcher);
addAttributeIfNotAlreadyCaptured(attributeMAp, ATTRIBUTE_TYPE.TSK_CARD_EXPIRATION, "expiration", matcher);
addAttributeIfNotAlreadyCaptured(attributeMAp, ATTRIBUTE_TYPE.TSK_CARD_SERVICE_CODE, "serviceCode", matcher);
addAttributeIfNotAlreadyCaptured(attributeMAp, ATTRIBUTE_TYPE.TSK_CARD_DISCRETIONARY, "discretionary", matcher);
addAttributeIfNotAlreadyCaptured(attributeMAp, ATTRIBUTE_TYPE.TSK_CARD_LRC, "LRC", matcher);
}
/**
* Parse the track 1 data from a KeywordHit and add it to the given
* artifact.
*
* @param attributeMap
* @param matcher
*/
static private void parseTrack1Data(Map<BlackboardAttribute.Type, BlackboardAttribute> attributeMap, Matcher matcher) {
// track 1 has all the fields present in track 2
parseTrack2Data(attributeMap, matcher);
//plus it also has the account holders name
addAttributeIfNotAlreadyCaptured(attributeMap, ATTRIBUTE_TYPE.TSK_NAME_PERSON, "name", matcher);
}
}

View File

@ -0,0 +1,517 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 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 com.google.common.base.CharMatcher;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.validator.routines.checkdigit.LuhnCheckDigit;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.TermsResponse.Term;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.datamodel.CreditCards;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Implements a regex query that will be performed as a two step operation. In
* the first step, the Solr terms component is used to find any terms in the
* index that match the regex. In the second step, term queries are executed for
* each matched term to produce the set of keyword hits for the regex.
*/
final class TermsComponentQuery implements KeywordSearchQuery {
private static final Logger LOGGER = Logger.getLogger(TermsComponentQuery.class.getName());
private static final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
private static final String SEARCH_HANDLER = "/terms"; //NON-NLS
private static final String SEARCH_FIELD = Server.Schema.CONTENT_WS.toString();
private static final int TERMS_SEARCH_TIMEOUT = 90 * 1000; // Milliseconds
private static final String CASE_INSENSITIVE = "case_insensitive"; //NON-NLS
private static final boolean DEBUG_FLAG = Version.Type.DEVELOPMENT.equals(Version.getBuildType());
private static final int MAX_TERMS_QUERY_RESULTS = 20000;
private final KeywordList keywordList;
private final Keyword keyword;
private String searchTerm;
private boolean searchTermIsEscaped;
private final List<KeywordQueryFilter> filters = new ArrayList<>(); // THIS APPEARS TO BE UNUSED
/*
* The following fields are part of the initial implementation of credit
* card account search and should be factored into another class when time
* permits.
*/
private static final Pattern CREDIT_CARD_NUM_PATTERN = Pattern.compile("(?<ccn>[3456]([ -]?\\d){11,18})"); //12-19 digits, with possible single spaces or dashes in between. First digit is 3,4,5, or 6 //NON-NLS
private static final LuhnCheckDigit CREDIT_CARD_NUM_LUHN_CHECK = new LuhnCheckDigit();
private static final Pattern CREDIT_CARD_TRACK1_PATTERN = Pattern.compile(
/*
* Track 1 is alphanumeric.
*
* This regex matches 12-19 digit ccns embeded in a track 1 formated
* string. This regex matches (and extracts groups) even if the
* entire track is not present as long as the part that is conforms
* to the track format.
*/
"(?:" //begin nested optinal group //NON-NLS
+ "%?" //optional start sentinal: % //NON-NLS
+ "B)?" //format code //NON-NLS
+ "(?<accountNumber>[3456]([ -]?\\d){11,18})" //12-19 digits, with possible single spaces or dashes in between. first digit is 3,4,5, or 6 //NON-NLS
+ "\\^" //separator //NON-NLS
+ "(?<name>[^^]{2,26})" //2-26 charachter name, not containing ^ //NON-NLS
+ "(?:\\^" //separator //NON-NLS
+ "(?:(?:\\^|(?<expiration>\\d{4}))" //separator or 4 digit expiration YYMM //NON-NLS
+ "(?:(?:\\^|(?<serviceCode>\\d{3}))"//separator or 3 digit service code //NON-NLS
+ "(?:(?<discretionary>[^?]*)" // discretionary data not containing separator //NON-NLS
+ "(?:\\?" // end sentinal: ? //NON-NLS
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
+ "?)?)?)?)?)?");//close nested optional groups //NON-NLS
private static final Pattern CREDIT_CARD_TRACK2_PATTERN = Pattern.compile(
/*
* Track 2 is numeric plus six punctuation symbolls :;<=>?
*
* This regex matches 12-19 digit ccns embeded in a track 2 formated
* string. This regex matches (and extracts groups) even if the
* entire track is not present as long as the part that is conforms
* to the track format.
*
*/
"[:;<=>?]?" //(optional)start sentinel //NON-NLS
+ "(?<accountNumber>[3456]([ -]?\\d){11,18})" //12-19 digits, with possible single spaces or dashes in between. first digit is 3,4,5, or 6 //NON-NLS
+ "(?:[:;<=>?]" //separator //NON-NLS
+ "(?:(?<expiration>\\d{4})" //4 digit expiration date YYMM //NON-NLS
+ "(?:(?<serviceCode>\\d{3})" //3 digit service code //NON-NLS
+ "(?:(?<discretionary>[^:;<=>?]*)" //discretionary data, not containing punctuation marks //NON-NLS
+ "(?:[:;<=>?]" //end sentinel //NON-NLS
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
+ "?)?)?)?)?)?"); //close nested optional groups //NON-NLS
private static final BlackboardAttribute.Type KEYWORD_SEARCH_DOCUMENT_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID);
/**
* Constructs an object that implements a regex query that will be performed
* as a two step operation. In the first step, the Solr terms component is
* used to find any terms in the index that match the regex. In the second
* step, term queries are executed for each matched term to produce the set
* of keyword hits for the regex.
*
* @param keywordList A keyword list that contains the keyword that provides
* the regex search term for the query.
* @param keyword The keyword that provides the regex search term for
* the query.
*/
// TODO: Why is both the list and the keyword added to the state of this
// object?
// TODO: Why is the search term not escaped and given substring wildcards,
// if needed, here in the constructor?
TermsComponentQuery(KeywordList keywordList, Keyword keyword) {
this.keywordList = keywordList;
this.keyword = keyword;
this.searchTerm = keyword.getSearchTerm();
}
/**
* Gets the keyword list that contains the keyword that provides the regex
* search term for the query.
*
* @return The keyword list.
*/
@Override
public KeywordList getKeywordList() {
return keywordList;
}
/**
* Gets the original search term for the query, without any escaping or, if
* it is a literal term, the addition of wildcards for a substring search.
*
* @return The original search term.
*/
@Override
public String getQueryString() {
return keyword.getSearchTerm();
}
/**
* Indicates whether or not the search term for the query is a literal term
* that needs have wildcards added to it to make the query a substring
* search.
*
* @return True or false.
*/
@Override
public boolean isLiteral() {
return false;
}
/**
* Adds wild cards to the search term for the query, which makes the query a
* substring search, if it is a literal search term.
*/
@Override
public void setSubstringQuery() {
searchTerm = ".*" + searchTerm + ".*";
}
/**
* Escapes the search term for the query.
*/
@Override
public void escape() {
searchTerm = Pattern.quote(keyword.getSearchTerm());
searchTermIsEscaped = true;
}
/**
* Indicates whether or not the search term has been escaped yet.
*
* @return True or false.
*/
@Override
public boolean isEscaped() {
return searchTermIsEscaped;
}
/**
* Gets the escaped search term for the query, assuming it has been escaped
* by a call to TermsComponentQuery.escape.
*
* @return The search term, possibly escaped.
*/
@Override
public String getEscapedQueryString() {
return this.searchTerm;
}
/**
* Indicates whether or not the search term is a valid regex.
*
* @return True or false.
*/
@Override
public boolean validate() {
if (searchTerm.isEmpty()) {
return false;
}
try {
Pattern.compile(searchTerm);
return true;
} catch (IllegalArgumentException ex) {
return false;
}
}
/**
* Does nothing, not applicable to a regex query, which always searches a
* field created specifically for regex sesarches.
*
* @param field The name of a Solr document field to search.
*/
@Override
public void setField(String field) {
}
/**
* Adds a filter to the query.
*
* @param filter The filter.
*/
// TODO: Document this better.
@Override
public void addFilter(KeywordQueryFilter filter) {
this.filters.add(filter);
}
/**
* Executes the regex query as a two step operation. In the first step, the
* Solr terms component is used to find any terms in the index that match
* the regex. In the second step, term queries are executed for each matched
* term to produce the set of keyword hits for the regex.
*
* @return A QueryResult object or null.
*
* @throws NoOpenCoreException
*/
// TODO: Make it so this cannot cause NPEs; this method should throw
// exceptions instead of logging them and returning null.
@Override
public QueryResults performQuery() throws NoOpenCoreException {
/*
* Do a query using the Solr terms component to find any terms in the
* index that match the regex.
*/
final SolrQuery termsQuery = new SolrQuery();
termsQuery.setRequestHandler(SEARCH_HANDLER);
termsQuery.setTerms(true);
termsQuery.setTermsRegexFlag(CASE_INSENSITIVE);
termsQuery.setTermsRegex(searchTerm);
termsQuery.addTermsField(SEARCH_FIELD);
termsQuery.setTimeAllowed(TERMS_SEARCH_TIMEOUT);
termsQuery.setShowDebugInfo(DEBUG_FLAG);
termsQuery.setTermsLimit(MAX_TERMS_QUERY_RESULTS);
List<Term> terms = null;
try {
terms = KeywordSearch.getServer().queryTerms(termsQuery).getTerms(SEARCH_FIELD);
} catch (KeywordSearchModuleException ex) {
LOGGER.log(Level.SEVERE, "Error executing the regex terms query: " + keyword.getSearchTerm(), ex); //NON-NLS
//TODO: this is almost certainly wrong and guaranteed to throw a NPE at some point!!!!
}
/*
* Do a term query for each term that matched the regex.
*/
QueryResults results = new QueryResults(this, keywordList);
for (Term term : terms) {
/*
* If searching for credit card account numbers, do a Luhn check on
* the term and discard it if it does not pass.
*/
if (keyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
Matcher matcher = CREDIT_CARD_NUM_PATTERN.matcher(term.getTerm());
matcher.find();
final String ccn = CharMatcher.anyOf(" -").removeFrom(matcher.group("ccn"));
if (false == CREDIT_CARD_NUM_LUHN_CHECK.isValid(ccn)) {
continue;
}
}
/*
* Do an ordinary query with the escaped term and convert the query
* results into a single list of keyword hits without duplicates.
*
* Note that the filters field appears to be unused. There is an old
* comment here, what does it mean? "Note: we can't set filter query
* on terms query but setting filter query on fileResults query will
* yield the same result." The filter is NOT being added to the term
* query.
*/
String escapedTerm = KeywordSearchUtil.escapeLuceneQuery(term.getTerm());
LuceneQuery termQuery = new LuceneQuery(keywordList, new Keyword(escapedTerm, true));
filters.forEach(termQuery::addFilter); // This appears to be unused
QueryResults termQueryResult = termQuery.performQuery();
Set<KeywordHit> termHits = new HashSet<>();
for (Keyword word : termQueryResult.getKeywords()) {
termHits.addAll(termQueryResult.getResults(word));
}
results.addResult(new Keyword(term.getTerm(), false), new ArrayList<>(termHits));
}
return results;
}
/**
* Converts the keyword hits for a given search term into artifacts.
*
* @param searchTerm The search term.
* @param hit The keyword hit.
* @param snippet The document snippet that contains the hit
* @param listName The name of the keyword list that contained the keyword
* for which the hit was found.
*
*
*
* @return An object that wraps an artifact and a mapping by id of its
* attributes.
*/
// TODO: Are we actually making meaningful use of the KeywordCachedArtifact
// class?
@Override
public KeywordCachedArtifact writeSingleFileHitsToBlackBoard(String searchTerm, KeywordHit hit, String snippet, String listName) {
/*
* Create either a "plain vanilla" keyword hit artifact with keyword and
* regex attributes, or a credit card account artifact with attributes
* parsed from from the snippet for the hit and looked up based on the
* parsed bank identifcation number.
*/
BlackboardArtifact newArtifact;
Collection<BlackboardAttribute> attributes = new ArrayList<>();
if (keyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, searchTerm));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, keyword.getSearchTerm()));
try {
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
return null;
}
} else {
/*
* Parse the credit card account attributes from the snippet for the
* hit.
*/
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name()));
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
if (hit.isArtifactHit()) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", searchTerm, hit.getSnippet(), hit.getArtifact().getArtifactID())); //NON-NLS
} else {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), hit.getContent().getId())); //NON-NLS
}
return null;
}
attributes.addAll(parsedTrackAttributeMap.values());
/*
* Look up the bank name, scheme, etc. attributes for the bank
* indentification number (BIN).
*/
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the
* hit.
*/
if (hit.getContent() instanceof AbstractFile) {
AbstractFile file = (AbstractFile) hit.getContent();
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
/*
* Create an account artifact.
*/
try {
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
return null;
}
}
if (StringUtils.isNotBlank(listName)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
}
if (snippet != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet));
}
if (hit.isArtifactHit()) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, hit.getArtifact().getArtifactID()));
}
try {
newArtifact.addAttributes(attributes);
KeywordCachedArtifact writeResult = new KeywordCachedArtifact(newArtifact);
writeResult.add(attributes);
return writeResult;
} catch (TskCoreException e) {
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
return null;
}
}
/**
* Parses the track 2 data from the snippet for a credit card account number
* hit and turns them into artifact attributes.
*
* @param attributesMap A map of artifact attribute objects, used to avoid
* creating duplicate attributes.
* @param matcher A matcher for the snippet.
*/
static private void parseTrack2Data(Map<BlackboardAttribute.Type, BlackboardAttribute> attributesMap, Matcher matcher) {
addAttributeIfNotAlreadyCaptured(attributesMap, ATTRIBUTE_TYPE.TSK_CARD_NUMBER, "accountNumber", matcher);
addAttributeIfNotAlreadyCaptured(attributesMap, ATTRIBUTE_TYPE.TSK_CARD_EXPIRATION, "expiration", matcher);
addAttributeIfNotAlreadyCaptured(attributesMap, ATTRIBUTE_TYPE.TSK_CARD_SERVICE_CODE, "serviceCode", matcher);
addAttributeIfNotAlreadyCaptured(attributesMap, ATTRIBUTE_TYPE.TSK_CARD_DISCRETIONARY, "discretionary", matcher);
addAttributeIfNotAlreadyCaptured(attributesMap, ATTRIBUTE_TYPE.TSK_CARD_LRC, "LRC", matcher);
}
/**
* Parses the track 1 data from the snippet for a credit card account number
* hit and turns them into artifact attributes. The track 1 data has the
* same fields as the track two data, plus the account holder's name.
*
* @param attributesMap A map of artifact attribute objects, used to avoid
* creating duplicate attributes.
* @param matcher A matcher for the snippet.
*/
static private void parseTrack1Data(Map<BlackboardAttribute.Type, BlackboardAttribute> attributeMap, Matcher matcher) {
parseTrack2Data(attributeMap, matcher);
addAttributeIfNotAlreadyCaptured(attributeMap, ATTRIBUTE_TYPE.TSK_NAME_PERSON, "name", matcher);
}
/**
* Creates an attribute of the the given type to the given artifact with a
* value parsed from the snippet for a credit account number hit.
*
* @param attributesMap A map of artifact attribute objects, used to avoid
* creating duplicate attributes.
* @param attrType The type of attribute to create.
* @param groupName The group name of the regular expression that was
* used to parse the attribute data.
* @param matcher A matcher for the snippet.
*/
static private void addAttributeIfNotAlreadyCaptured(Map<BlackboardAttribute.Type, BlackboardAttribute> attributeMap, ATTRIBUTE_TYPE attrType, String groupName, Matcher matcher) {
BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrType);
attributeMap.computeIfAbsent(type, (BlackboardAttribute.Type t) -> {
String value = matcher.group(groupName);
if (attrType.equals(ATTRIBUTE_TYPE.TSK_CARD_NUMBER)) {
value = CharMatcher.anyOf(" -").removeFrom(value);
}
if (StringUtils.isNotBlank(value)) {
return new BlackboardAttribute(attrType, MODULE_NAME, value);
}
return null;
});
}
}

View File

@ -99,7 +99,7 @@ final class XmlKeywordSearchList extends KeywordSearchList {
doc.appendChild(rootEl);
for (String listName : theLists.keySet()) {
if (theLists.get(listName).isLocked() == true) {
if (theLists.get(listName).isEditable() == true) {
continue;
}
KeywordList list = theLists.get(listName);
@ -123,13 +123,13 @@ final class XmlKeywordSearchList extends KeywordSearchList {
for (Keyword keyword : keywords) {
Element keywordEl = doc.createElement(KEYWORD_EL);
String literal = keyword.isLiteral() ? "true" : "false"; //NON-NLS
String literal = keyword.searchTermIsLiteral() ? "true" : "false"; //NON-NLS
keywordEl.setAttribute(KEYWORD_LITERAL_ATTR, literal);
BlackboardAttribute.ATTRIBUTE_TYPE selectorType = keyword.getType();
BlackboardAttribute.ATTRIBUTE_TYPE selectorType = keyword.getArtifactAttributeType();
if (selectorType != null) {
keywordEl.setAttribute(KEYWORD_SELECTOR_ATTR, selectorType.getLabel());
}
keywordEl.setTextContent(keyword.getQuery());
keywordEl.setTextContent(keyword.getSearchTerm());
listEl.appendChild(keywordEl);
}
rootEl.appendChild(listEl);
@ -199,7 +199,7 @@ final class XmlKeywordSearchList extends KeywordSearchList {
String selector = wordEl.getAttribute(KEYWORD_SELECTOR_ATTR);
if (!selector.equals("")) {
BlackboardAttribute.ATTRIBUTE_TYPE selectorType = BlackboardAttribute.ATTRIBUTE_TYPE.fromLabel(selector);
keyword.setType(selectorType);
keyword.setArtifactAttributeType(selectorType);
}
words.add(keyword);

View File

@ -1,13 +1,15 @@
---------------- VERSION 4.2.0 --------------
Improvements:
- Credit card account search
- Encoding/decoding of extracted files to avoid anti-virus alerts/quarantine
- Options panel for managing custom tag names
- Options panel for setting external viewer associations
- Keyboard shortcut for applying Bookmark tags
- Improved PhotoRec carver ingest module cancellation responsiveness
- Results content viewer formats dates instead of showing raw seconds since epoch
- Update to PostgreSQL 9.5
- Credit card account search.
- Encoding/decoding of extracted files to avoid anti-virus alerts/quarantine.
- Ingest history (start time, end time, status, which versions of which ingest modules were run).
- Ingest history used to warn before doing redundant analysis.
- Options panel for managing custom tag names.
- Options panel for setting external viewer associations.
- Keyboard shortcut for applying Bookmark tags.
- Improved PhotoRec carver ingest module cancellation responsiveness.
- Results content viewer formats dates.
- Update to PostgreSQL 9.5.
- Assorted bug fixes and minor enhancements.
---------------- VERSION 4.1.1 --------------

View File

@ -1,5 +1,5 @@
#Updated by build script
#Wed, 12 Oct 2016 13:08:27 -0400
#Sat, 22 Oct 2016 14:27:47 -0400
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314
SPLASH_WIDTH=538

View File

@ -1,4 +1,4 @@
#Updated by build script
#Wed, 12 Oct 2016 13:08:27 -0400
#Sat, 22 Oct 2016 14:27:47 -0400
CTL_MainWindow_Title=Autopsy 4.2.0
CTL_MainWindow_Title_No_Project=Autopsy 4.2.0

View File

@ -43,68 +43,40 @@
<!-- copy 64-bit dlls into the installer folder -->
<target name="copyWinTskLibs64ToBaseDir" if="win64.TskLib.exists">
<fileset dir="${win64.TskLib.path}" id="win64dlls">
<include name="libewf.dll" />
<include name="libvmdk.dll"/>
<include name="libvhdi.dll"/>
<include name="zlib.dll"/>
</fileset>
<fileset dir="${win64.TskLib.postgres_path}" id="postgres64dlls">
<include name="libeay32.dll"/>
<include name="ssleay32.dll"/>
<include name="libintl-8.dll"/>
<include name="libiconv-2.dll"/>
<include name="libpq.dll"/>
<include name="msvcr120.dll"/>
<include name="*.dll" />
<exclude name="libtsk_jni.dll"/>
</fileset>
<copy todir="${amd64}" overwrite="true">
<fileset refid="win64dlls" />
<fileset refid="postgres64dlls" />
</copy>
<copy todir="${x86_64}" overwrite="true">
<fileset refid="win64dlls" />
<fileset refid="postgres64dlls" />
</copy>
</target>
<!-- copy 32-bit dlls into the installer folder -->
<target name="copyWinTskLibs32ToBaseDir" if="win32.TskLib.exists">
<fileset dir="${win32.TskLib.path}" id="win32dlls">
<include name="zlib.dll" />
<include name="libvmdk.dll"/>
<include name="libvhdi.dll"/>
<include name="libewf.dll"/>
</fileset>
<fileset dir="${win32.TskLib.postgres_path}" id="postgres32dlls">
<include name="libeay32.dll"/>
<include name="ssleay32.dll"/>
<include name="libintl-8.dll"/>
<include name="libiconv-2.dll"/>
<include name="libpq.dll"/>
<include name="msvcr120.dll"/>
<include name="*.dll" />
<exclude name="libtsk_jni.dll"/>
</fileset>
<copy todir="${i386}" overwrite="true">
<fileset refid="win32dlls" />
<fileset refid="postgres32dlls" />
</copy>
<copy todir="${x86}" overwrite="true">
<fileset refid="win32dlls" />
<fileset refid="postgres32dlls" />
</copy>
<copy todir="${i586}" overwrite="true">
<fileset refid="win32dlls" />
<fileset refid="postgres32dlls" />
</copy>
<copy todir="${i686}" overwrite="true">
<fileset refid="win32dlls" />
<fileset refid="postgres32dlls" />
</copy>
</target>
@ -115,57 +87,4 @@
<antcall target="copyWinTskLibs64ToBaseDir" inheritRefs="true" />
</target>
<!-- CRT LIBS TO ZIP - gets called from build.xml -->
<target name="copyLibsToZip" depends="copyCRT32ToZIP,copyCRT64ToZIP"/>
<target name="copyCRT32ToZIP">
<!-- verify we have the 32-bit dlls -->
<property name="CRT32.path" value="${thirdparty.dir}/crt/win32"/>
<available file="${CRT32.path}" property="crtFound"/>
<fail unless="crtFound" message="32-bit CRT not found in the thirdparty repo in path: ${CRT32.path}"/>
<!-- copy them from third party -->
<property name="zip-lib-path" value="${zip-tmp}/${app.name}/${app.name}/modules/lib/"/>
<fileset dir="${CRT32.path}" id="crt32dlls">
<include name="*.dll"/>
</fileset>
<copy todir="${zip-lib-path}/x86" overwrite="true">
<fileset refid="crt32dlls"/>
</copy>
<copy todir="${zip-lib-path}/i386" overwrite="true">
<fileset refid="crt32dlls"/>
</copy>
<copy todir="${zip-lib-path}/i586" overwrite="true">
<fileset refid="crt32dlls"/>
</copy>
<copy todir="${zip-lib-path}/i686" overwrite="true">
<fileset refid="crt32dlls"/>
</copy>
</target>
<target name="copyCRT64ToZIP">
<!-- Verify we have the 64-bit -->
<property name="CRT64.path" value="${thirdparty.dir}/crt/win64"/>
<available file="${CRT64.path}" property="crtFound"/>
<fail unless="crtFound" message="64-bit CRT not found in the thirdparty repo in path: ${CRT64.path}"/>
<!-- Copy the libs -->
<property name="zip-lib-path" value="${zip-tmp}/${app.name}/${app.name}/modules/lib/"/>
<fileset dir="${CRT64.path}" id="crt64dlls">
<include name="*.dll"/>
</fileset>
<copy todir="${zip-lib-path}/x86_64" overwrite="true">
<fileset refid="crt64dlls"/>
</copy>
<copy todir="${zip-lib-path}/amd64" overwrite="true">
<fileset refid="crt64dlls"/>
</copy>
</target>
</project>

View File

@ -92,8 +92,6 @@
</then>
</if>
<antcall target="copyLibsToZip"/>
<property name="app.property.file" value="${zip-tmp}/${app.name}/etc/${app.name}.conf" />
<!-- for Japanese localized version add option: -Duser.language=ja -->
<property name="jvm.options" value="&quot;--branding ${app.name} -J-Xms24m -J-XX:MaxPermSize=128M -J-Xverify:none -J-Xdock:name=${app.title}&quot;" />

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 4.1
PROJECT_NUMBER = 4.2
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@ -1025,7 +1025,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = 4.1
HTML_OUTPUT = 4.2
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).

View File

@ -1063,7 +1063,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = api-docs/4.1/
HTML_OUTPUT = api-docs/4.2/
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).

View File

@ -6,8 +6,8 @@ app.name=${branding.token}
### if left unset, version will default to today's date
app.version=4.2.0
### build.type must be one of: DEVELOPMENT, RELEASE
build.type=RELEASE
#build.type=DEVELOPMENT
#build.type=RELEASE
build.type=DEVELOPMENT
project.org.sleuthkit.autopsy.imagegallery=ImageGallery
update_versions=false

View File

@ -1,9 +0,0 @@
REM Updates the 32-bit and 64-bit VS Runtime dlls
REM Needs to be run from a 64-bit command prompt
REM Otherwise Windows will put 32-bit dlls in system32
copy c:\windows\system32\msvcr100.dll win64
copy c:\windows\system32\msvcp100.dll win64
copy c:\windows\system32\msvcr120.dll win64
copy c:\windows\sysWoW64\msvcr100.dll win32
copy c:\windows\sysWow64\msvcp100.dll win32
copy c:\windows\sysWow64\msvcr120.dll win32

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.