mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 01:07:42 +00:00
Merge remote-tracking branch 'upstream/release-4.7.0' into 967-don't-show-secondary-relationships-by-default
This commit is contained in:
commit
6c4573f15b
3
.gitignore
vendored
3
.gitignore
vendored
@ -78,3 +78,6 @@ hs_err_pid*.log
|
||||
/RecentActivity/release/
|
||||
/CentralRepository/release/
|
||||
|
||||
*.img
|
||||
*.vhd
|
||||
*.E01
|
||||
|
22
.travis.yml
Normal file
22
.travis.yml
Normal file
@ -0,0 +1,22 @@
|
||||
language: java
|
||||
sudo: required
|
||||
dist: trusty
|
||||
os:
|
||||
- linux
|
||||
env:
|
||||
global:
|
||||
- TSK_HOME=$TRAVIS_BUILD_DIR/sleuthkit/sleuthkit
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
before_install:
|
||||
- git clone https://github.com/sleuthkit/sleuthkit.git sleuthkit/sleuthkit
|
||||
install:
|
||||
- sudo apt-get install testdisk
|
||||
- cd sleuthkit/sleuthkit
|
||||
- sh install-sleuthkit.sh
|
||||
script:
|
||||
- cd $TRAVIS_BUILD_DIR/
|
||||
- ant build
|
||||
- cd Core/
|
||||
- xvfb-run ant test
|
||||
|
@ -12,7 +12,7 @@
|
||||
<property name="thirdparty.dir" value="${basedir}/../thirdparty" />
|
||||
<property name="modules.dir" value="${basedir}/release/modules/" />
|
||||
<property name="ext.dir" value="${modules.dir}/ext" />
|
||||
<property name="test-input" location="test"/>
|
||||
<property name="test-input" location="test/qa-functional/data"/>
|
||||
|
||||
<target name="get-InternalPythonModules" description="get internal python modules">
|
||||
<copy todir="release/InternalPythonModules" >
|
||||
@ -83,6 +83,7 @@
|
||||
</target>
|
||||
|
||||
<target name="getImageFile">
|
||||
<mkdir dir="${basedir}/test/qa-functional/data"/>
|
||||
<get src="https://drive.google.com/uc?id=0BxdBkzm5VKGNT0dGY0dqcHVsU3M" dest="${test-input}/filter_test1.img" skipexisting="true"/>
|
||||
</target>
|
||||
<target name="get-deps" depends="init-ivy,getTSKJars,get-thirdparty-dependencies,get-InternalPythonModules, download-binlist, getImageFile">
|
||||
|
@ -176,9 +176,15 @@ public abstract class AbstractSqlEamDb implements EamDb {
|
||||
* @returns New Case class with populated database ID
|
||||
*/
|
||||
@Override
|
||||
public CorrelationCase newCase(CorrelationCase eamCase) throws EamDbException {
|
||||
Connection conn = connect();
|
||||
public synchronized CorrelationCase newCase(CorrelationCase eamCase) throws EamDbException {
|
||||
|
||||
// check if there is already an existing CorrelationCase for this Case
|
||||
CorrelationCase cRCase = getCaseByUUID(eamCase.getCaseUUID());
|
||||
if (cRCase != null) {
|
||||
return cRCase;
|
||||
}
|
||||
|
||||
Connection conn = connect();
|
||||
PreparedStatement preparedStatement = null;
|
||||
|
||||
String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
|
||||
|
@ -39,7 +39,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.FileTypeViewer;
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 3)
|
||||
public class FileViewer extends javax.swing.JPanel implements DataContentViewer {
|
||||
|
||||
private static final int CONFIDENCE_LEVEL = 7;
|
||||
private static final int CONFIDENCE_LEVEL = 5;
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName());
|
||||
|
||||
|
@ -503,7 +503,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
||||
rtfbodyTextPane.setText("");
|
||||
htmlbodyTextPane.setText("");
|
||||
textbodyTextArea.setText("");
|
||||
drp.setNode(null);
|
||||
showImagesToggleButton.setEnabled(false);
|
||||
msgbodyTabbedPane.setEnabled(false);
|
||||
}
|
||||
@ -546,7 +545,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
||||
@Override
|
||||
public int isPreferred(Node node) {
|
||||
if (isSupported(node)) {
|
||||
return 6;
|
||||
return 7;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentviewers;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
@ -36,12 +37,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
@ -71,7 +68,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
private Connection connection;
|
||||
private int numRows; // num of rows in the selected table
|
||||
private int currPage = 0; // curr page of rows being displayed
|
||||
private SwingWorker<? extends Object, ? extends Object> worker;
|
||||
|
||||
/**
|
||||
* Constructs a file content viewer for SQLite database files.
|
||||
@ -213,6 +209,7 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
currPage++;
|
||||
if (currPage * ROWS_PER_PAGE > numRows) {
|
||||
nextPageButton.setEnabled(false);
|
||||
@ -223,9 +220,12 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
// read and display a page of rows
|
||||
String tableName = (String) this.tablesDropdownList.getSelectedItem();
|
||||
readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}//GEN-LAST:event_nextPageButtonActionPerformed
|
||||
|
||||
private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
|
||||
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
currPage--;
|
||||
if (currPage == 1) {
|
||||
prevPageButton.setEnabled(false);
|
||||
@ -236,6 +236,7 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
// read and display a page of rows
|
||||
String tableName = (String) this.tablesDropdownList.getSelectedItem();
|
||||
readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}//GEN-LAST:event_prevPageButtonActionPerformed
|
||||
|
||||
private void tablesDropdownListActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tablesDropdownListActionPerformed
|
||||
@ -244,7 +245,9 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
if (null == tableName) {
|
||||
return;
|
||||
}
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
selectTable(tableName);
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}//GEN-LAST:event_tablesDropdownListActionPerformed
|
||||
|
||||
|
||||
@ -269,8 +272,10 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
@Override
|
||||
public void setFile(AbstractFile file) {
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
sqliteDbFile = file;
|
||||
processSQLiteFile();
|
||||
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -294,12 +299,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
}
|
||||
}
|
||||
|
||||
// delete last temp file
|
||||
if (null != tmpDbFile) {
|
||||
tmpDbFile.delete();
|
||||
tmpDbFile = null;
|
||||
}
|
||||
|
||||
sqliteDbFile = null;
|
||||
}
|
||||
|
||||
@ -315,34 +314,40 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
"SQLiteViewer.errorMessage.failedToinitJDBCDriver=The JDBC driver for SQLite could not be loaded.",
|
||||
"# {0} - exception message", "SQLiteViewer.errorMessage.unexpectedError=An unexpected error occurred:\n{0).",})
|
||||
private void processSQLiteFile() {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
|
||||
tablesDropdownList.removeAllItems();
|
||||
});
|
||||
new SwingWorker<Map<String, String>, Void>() {
|
||||
@Override
|
||||
protected Map<String, String> doInBackground() throws NoCurrentCaseException, TskCoreException, IOException, SQLException, ClassNotFoundException {
|
||||
|
||||
// Copy the file to temp folder
|
||||
String tmpDBPathName = Case.getOpenCase().getTempDirectory() + File.separator + sqliteDbFile.getName();
|
||||
String tmpDBPathName;
|
||||
try {
|
||||
tmpDBPathName = Case.getOpenCase().getTempDirectory() + File.separator + sqliteDbFile.getName();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Current case has been closed", ex); //NON-NLS
|
||||
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_noCurrentCase());
|
||||
return;
|
||||
}
|
||||
|
||||
tmpDbFile = new File(tmpDBPathName);
|
||||
if (! tmpDbFile.exists()) {
|
||||
try {
|
||||
ContentUtils.writeToFile(sqliteDbFile, tmpDbFile);
|
||||
|
||||
// Look for any meta files associated with this DB - WAL, SHM, etc.
|
||||
findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal");
|
||||
findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm");
|
||||
} catch (IOException | NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to create temp copy of DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToExtractFile());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Load the SQLite JDBC driver, if necessary.
|
||||
Class.forName("org.sqlite.JDBC"); //NON-NLS
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS
|
||||
|
||||
// Query the file for the table names and schemas.
|
||||
return getTables();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
super.done();
|
||||
try {
|
||||
Map<String, String> dbTablesMap = get();
|
||||
Map<String, String> dbTablesMap = getTables();
|
||||
if (dbTablesMap.isEmpty()) {
|
||||
tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry());
|
||||
tablesDropdownList.setEnabled(false);
|
||||
@ -351,32 +356,13 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
tablesDropdownList.addItem(tableName);
|
||||
});
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Interrupted while opening SQLite database file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_interrupted());
|
||||
} catch (ExecutionException ex) {
|
||||
String errorMessage;
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause instanceof NoCurrentCaseException) {
|
||||
logger.log(Level.SEVERE, "Current case has been closed", ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_noCurrentCase();
|
||||
} else if (cause instanceof TskCoreException || cause instanceof IOException) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to create temp copy of DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_failedToExtractFile();
|
||||
} else if (cause instanceof SQLException) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to get tables from DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase();
|
||||
} else if (cause instanceof ClassNotFoundException) {
|
||||
} catch (ClassNotFoundException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to initialize JDBC SQLite '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_failedToinitJDBCDriver();
|
||||
} else {
|
||||
logger.log(Level.SEVERE, String.format("Unexpected exception while processing DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
errorMessage = Bundle.SQLiteViewer_errorMessage_unexpectedError(cause.getLocalizedMessage());
|
||||
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToinitJDBCDriver());
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to get tables from DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase());
|
||||
}
|
||||
MessageNotifyUtil.Message.error(errorMessage);
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -436,41 +422,12 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
"SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}"
|
||||
})
|
||||
private void selectTable(String tableName) {
|
||||
if (worker != null && !worker.isDone()) {
|
||||
worker.cancel(false);
|
||||
worker = null;
|
||||
}
|
||||
|
||||
worker = new SwingWorker<Integer, Void>() {
|
||||
@Override
|
||||
protected Integer doInBackground() throws Exception {
|
||||
try (Statement statement = connection.createStatement();
|
||||
ResultSet resultSet = statement.executeQuery(
|
||||
"SELECT count (*) as count FROM " + tableName)) { //NON-NLS{
|
||||
|
||||
Statement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
statement = connection.createStatement();
|
||||
resultSet = statement.executeQuery(
|
||||
"SELECT count (*) as count FROM " + tableName); //NON-NLS
|
||||
|
||||
return resultSet.getInt("count");
|
||||
} catch (SQLException ex) {
|
||||
throw ex;
|
||||
} finally {
|
||||
if (null != resultSet) {
|
||||
resultSet.close();
|
||||
}
|
||||
if (null != statement) {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
super.done();
|
||||
try {
|
||||
|
||||
numRows = get();
|
||||
numRows = resultSet.getInt("count");
|
||||
numEntriesField.setText(numRows + " entries");
|
||||
|
||||
currPage = 1;
|
||||
@ -487,93 +444,34 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
selectedTableView.setupTable(Collections.emptyList());
|
||||
}
|
||||
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "Interrupted while getting row count from table " + tableName, ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getMessage(),
|
||||
Bundle.SQLiteViewer_selectTable_errorText(tableName),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Unexpected exception while getting row count from table " + tableName, ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getCause().getMessage(),
|
||||
Bundle.SQLiteViewer_selectTable_errorText(tableName),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to load table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_selectTable_errorText(tableName));
|
||||
}
|
||||
}
|
||||
};
|
||||
worker.execute();
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"# {0} - tableName",
|
||||
"SQLiteViewer.readTable.errorText=Error getting rows for table: {0}"})
|
||||
private void readTable(String tableName, int startRow, int numRowsToRead) {
|
||||
|
||||
if (worker != null && !worker.isDone()) {
|
||||
worker.cancel(false);
|
||||
worker = null;
|
||||
}
|
||||
|
||||
worker = new SwingWorker<ArrayList<Map<String, Object>>, Void>() {
|
||||
@Override
|
||||
protected ArrayList<Map<String, Object>> doInBackground() throws Exception {
|
||||
|
||||
Statement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
statement = connection.createStatement();
|
||||
resultSet = statement.executeQuery(
|
||||
try (
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet resultSet = statement.executeQuery(
|
||||
"SELECT * FROM " + tableName
|
||||
+ " LIMIT " + Integer.toString(numRowsToRead)
|
||||
+ " OFFSET " + Integer.toString(startRow - 1)
|
||||
); //NON-NLS
|
||||
+ " OFFSET " + Integer.toString(startRow - 1))) {
|
||||
|
||||
return resultSetToArrayList(resultSet);
|
||||
} catch (SQLException ex) {
|
||||
throw ex;
|
||||
} finally {
|
||||
if (null != resultSet) {
|
||||
resultSet.close();
|
||||
}
|
||||
if (null != statement) {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
|
||||
if (isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.done();
|
||||
try {
|
||||
ArrayList<Map<String, Object>> rows = get();
|
||||
ArrayList<Map<String, Object>> rows = resultSetToArrayList(resultSet);
|
||||
if (Objects.nonNull(rows)) {
|
||||
selectedTableView.setupTable(rows);
|
||||
} else {
|
||||
selectedTableView.setupTable(Collections.emptyList());
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "Interrupted while reading table " + tableName, ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getMessage(),
|
||||
Bundle.SQLiteViewer_readTable_errorText(tableName),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Unexpected exception while reading table " + tableName, ex); //NON-NLS
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getCause().getMessage(),
|
||||
Bundle.SQLiteViewer_readTable_errorText(tableName),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to read table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
|
||||
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_readTable_errorText(tableName));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
worker.execute();
|
||||
}
|
||||
|
||||
@NbBundle.Messages("SQLiteViewer.BlobNotShown.message=BLOB Data not shown")
|
||||
private ArrayList<Map<String, Object>> resultSetToArrayList(ResultSet rs) throws SQLException {
|
||||
|
@ -89,15 +89,45 @@ public interface DataContentViewer {
|
||||
* subjective, but the idea is that Autopsy wants to display the most
|
||||
* relevant tab. The more generic the viewer, the lower the return value
|
||||
* should be. This will only be called on viewers that support the given
|
||||
* node.
|
||||
* node (i.e., isSupported() has already returned true).
|
||||
*
|
||||
* The following are some examples of the current levels in use. If the selected
|
||||
* node is an artifact, the level may be determined by both the artifact and its
|
||||
* associated file.
|
||||
*
|
||||
* Level 7 - Based on the artifact, if any, in the selected node and specific
|
||||
* to an artifact type or types. Current content viewers that can return level 7 are
|
||||
* the Messages tab (only supported for email and SMS) and the Indexed Text tab
|
||||
* when the selected node is a Keyword Search hit.
|
||||
*
|
||||
* Level 6 - Based on the artifact, if any, in the selected node but not
|
||||
* restricted to particular types. The current content viewer that can return level 6
|
||||
* is the Results tab. It returns this level for most artifact types,
|
||||
* unless the associated file is assumed to be of greater interest (for example,
|
||||
* a Hash Set Hit will not be level 6 because the file itself is of greater interest).
|
||||
*
|
||||
* Level 5 - Based on the file in the selected node and very specific to the file type. The current
|
||||
* content viewer that will return level 5 is
|
||||
* the Application tab, which supports media files (such as images) and
|
||||
* certain types of databases.
|
||||
*
|
||||
* Level 4 - Based on the file in the selected node but fairly general.
|
||||
* Currently this is the level returned by the Indexed Text tab if Keyword Search
|
||||
* has been run (unless the node is a Keyword Search hit or a Credit Card account).
|
||||
* This is the default tab for most files.
|
||||
*
|
||||
* Level 3 - Based on the artifact, if any, in the selected node where the
|
||||
* artifact is thought to be of less interest than the associated file. This
|
||||
* level is returned by the Results tab for artifacts like Hash Set Hits.
|
||||
*
|
||||
* Level 1 - Very general and should always be available. The Hex, Strings, and Metadata tabs
|
||||
* are all this level
|
||||
*
|
||||
* Level 0 - For cases where the content viewer should never be displayed by default.
|
||||
*
|
||||
* @param node Node to check for preference
|
||||
*
|
||||
* @return an int (0-10) higher return means the viewer has higher priority
|
||||
* 0 means not supported 1 to 2 means the module will display all
|
||||
* file types (such as the hex viewer) 3-10 are prioritized by
|
||||
* Content viewer developer. Modules that operate on very few file
|
||||
* types should be towards 10.
|
||||
*/
|
||||
public int isPreferred(Node node);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ DataContentViewerString.pageLabel2.text=Page
|
||||
# Product Information panel
|
||||
LBL_Description=<div style=\"font-size: 12pt; font-family: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif;\">\n <b>Product Version:</b> {0} ({9}) <br><b>Sleuth Kit Version:</b> {7} <br><b>Netbeans RCP Build:</b> {8} <br> <b>Java:</b> {1}; {2}<br> <b>System:</b> {3}; {4}; {5}<br><b>Userdir:</b> {6}</div>
|
||||
Format_OperatingSystem_Value={0} version {1} running on {2}
|
||||
LBL_Copyright=<div style\="font-size\: 12pt; font-family\: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools. <br><ul><li>General Information: <a style\="color\: \#1E2A60;" href\="http\://www.sleuthkit.org">http\://www.sleuthkit.org</a>.</li><li>Training: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright © 2003-2017. </div>
|
||||
LBL_Copyright=<div style\="font-size\: 12pt; font-family\: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools. <br><ul><li>General Information: <a style\="color\: \#1E2A60;" href\="http\://www.sleuthkit.org">http\://www.sleuthkit.org</a>.</li><li>Training: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style\="color\: \#1E2A60;" href\="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright © 2003-2018. </div>
|
||||
URL_ON_IMG=http://www.sleuthkit.org/
|
||||
URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.6.0/
|
||||
FILE_FOR_LOCAL_HELP=file:///
|
||||
|
@ -477,7 +477,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())) {
|
||||
return 3;
|
||||
} else {
|
||||
return 5;
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -19,21 +19,31 @@
|
||||
package org.sleuthkit.autopsy.filesearch;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
import java.text.ParseException;
|
||||
import java.util.Locale;
|
||||
import javax.swing.JComboBox;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.python.icu.text.NumberFormat;
|
||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author pmartel
|
||||
* Filter search size input.
|
||||
*/
|
||||
class SizeSearchFilter extends AbstractFileSearchFilter<SizeSearchPanel> {
|
||||
|
||||
/**
|
||||
* Instantiate a SizeSearchFilter object for a new SizeSearchPanel.
|
||||
*/
|
||||
SizeSearchFilter() {
|
||||
this(new SizeSearchPanel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a SizeSearchFilter object for an existing SizeSearchPanel.
|
||||
*
|
||||
* @param component The SizeSearchPanel instance.
|
||||
*/
|
||||
SizeSearchFilter(SizeSearchPanel component) {
|
||||
super(component);
|
||||
}
|
||||
@ -53,6 +63,14 @@ class SizeSearchFilter extends AbstractFileSearchFilter<SizeSearchPanel> {
|
||||
return "size " + operator + " " + size; //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the comparison operator associated with the size comparison
|
||||
* drop-down selection.
|
||||
*
|
||||
* @param compare The drop-down component.
|
||||
*
|
||||
* @return The operator.
|
||||
*/
|
||||
private String compareComboBoxToOperator(JComboBox<String> compare) {
|
||||
String compareSize = compare.getSelectedItem().toString();
|
||||
|
||||
@ -83,12 +101,12 @@ class SizeSearchFilter extends AbstractFileSearchFilter<SizeSearchPanel> {
|
||||
String input = this.getComponent().getSizeTextField().getText();
|
||||
|
||||
try {
|
||||
int inputInt = Integer.parseInt(input);
|
||||
int inputInt = NumberFormat.getNumberInstance(Locale.US).parse(input).intValue();
|
||||
if (inputInt < 0) {
|
||||
setLastError(Bundle.SizeSearchFilter_errorMessage_nonNegativeNumber());
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException | NullPointerException e) {
|
||||
} catch (ParseException ex) {
|
||||
setLastError(Bundle.SizeSearchFilter_errorMessage_notANumber());
|
||||
return false;
|
||||
}
|
||||
|
@ -410,11 +410,18 @@ final class IngestTasksScheduler {
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the file is a member of the file ingest filter that is being
|
||||
* applied to the current run of ingest, checks if unallocated space
|
||||
* should be processed inside call to fileIsMemberOf
|
||||
* Ensures that all directories, files which are members of the ingest
|
||||
* file filter, and unallocated blocks (when processUnallocated is
|
||||
* enabled) all continue to be processed. AbstractFiles which do not
|
||||
* meet one of these criteria will be skipped.
|
||||
*
|
||||
* An additional check to see if unallocated space should be processed
|
||||
* is part of the FilesSet.fileIsMemberOf() method.
|
||||
*
|
||||
* This code may need to be updated when
|
||||
* TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS comes into use by Autopsy.
|
||||
*/
|
||||
if (!file.isDir() && task.getIngestJob().getFileIngestFilter().fileIsMemberOf(file) == null) {
|
||||
if (!file.isDir() && !shouldBeCarved(task) && !fileAcceptedByFilter(task)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -462,6 +469,30 @@ final class IngestTasksScheduler {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not a file should be carved for a data source ingest
|
||||
* ingest job.
|
||||
*
|
||||
* @param task The file ingest task for the file.
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
private static boolean shouldBeCarved(final FileIngestTask task) {
|
||||
return task.getIngestJob().shouldProcessUnallocatedSpace() && task.getFile().getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a file is accepted (passes) the file filter for a data
|
||||
* source ingest job.
|
||||
*
|
||||
* @param task The file ingest task for the file.
|
||||
*
|
||||
* @return True or false.
|
||||
*/
|
||||
private static boolean fileAcceptedByFilter(final FileIngestTask task) {
|
||||
return !(task.getIngestJob().getFileIngestFilter().fileIsMemberOf(task.getFile()) == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not a collection of ingest tasks includes a task for a
|
||||
* given data source ingest job.
|
||||
|
Binary file not shown.
@ -23,6 +23,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import junit.framework.TestCase;
|
||||
@ -32,6 +33,7 @@ import org.sleuthkit.autopsy.casemodule.CaseActionException;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseDetails;
|
||||
import junit.framework.Test;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.netbeans.junit.NbTestCase;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.python.icu.impl.Assert;
|
||||
import org.sleuthkit.autopsy.casemodule.ImageDSProcessor;
|
||||
@ -40,18 +42,23 @@ import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory;
|
||||
import org.sleuthkit.autopsy.modules.interestingitems.FilesSet;
|
||||
import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule;
|
||||
import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.MetaTypeCondition;
|
||||
import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.ParentPathCondition;
|
||||
import org.sleuthkit.autopsy.testutils.DataSourceProcessorRunner;
|
||||
import org.sleuthkit.autopsy.testutils.DataSourceProcessorRunner.ProcessorCallback;
|
||||
import org.sleuthkit.autopsy.testutils.IngestJobRunner;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
public class IngestFileFiltersTest extends TestCase {
|
||||
public class IngestFileFiltersTest extends NbTestCase {
|
||||
|
||||
private static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), "IngestFileFiltersTest");
|
||||
private static final File CASE_DIR = new File(CASE_DIRECTORY_PATH.toString());
|
||||
private static final Path IMAGE_PATH = Paths.get("test/filter_test1.img");
|
||||
private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(),"filter_test1.img");
|
||||
|
||||
public static Test suite() {
|
||||
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestFileFiltersTest.class).
|
||||
@ -60,6 +67,10 @@ public class IngestFileFiltersTest extends TestCase {
|
||||
return conf.suite();
|
||||
}
|
||||
|
||||
public IngestFileFiltersTest(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() {
|
||||
// Delete the test directory, if it exists
|
||||
@ -116,28 +127,48 @@ public class IngestFileFiltersTest extends TestCase {
|
||||
assertFalse(CASE_DIR.exists());
|
||||
}
|
||||
|
||||
public void testFileType() {
|
||||
public void testBasicDir() {
|
||||
HashMap<String, Rule> rule = new HashMap<>();
|
||||
rule.put("Rule", new Rule("testFileType", null, new MetaTypeCondition(MetaTypeCondition.Type.FILES), new ParentPathCondition("dir1"), null, null, null));
|
||||
//Filter for dir1 and no unallocated space
|
||||
FilesSet Files_Dirs_Unalloc_Ingest_Filter = new FilesSet("Filter", "Filter to find all files in dir1.", false, true, rule);
|
||||
|
||||
try {
|
||||
Case openCase = Case.getOpenCase();
|
||||
runIngestJob(openCase.getDataSources());
|
||||
runIngestJob(openCase.getDataSources(), Files_Dirs_Unalloc_Ingest_Filter);
|
||||
FileManager fileManager = openCase.getServices().getFileManager();
|
||||
List<AbstractFile> results = fileManager.findFiles("file.jpg", "dir1");
|
||||
String mimeType = results.get(0).getMIMEType();
|
||||
assertEquals("image/jpeg", mimeType);
|
||||
|
||||
results = fileManager.findFiles("%%");
|
||||
|
||||
for (AbstractFile file : results) {
|
||||
//All files in dir1 should have MIME type, except '.' '..' and slack files
|
||||
if (file.getParentPath().equalsIgnoreCase("/dir1/")) {
|
||||
if (!(file.getName().equals(".") || file.getName().equals("..") || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) {
|
||||
String errMsg = String.format("File %s (objId=%d) unexpectedly blocked by the file filter.", file.getName(), file.getId());
|
||||
assertTrue(errMsg, !(file.getMIMEType() == null || file.getMIMEType().isEmpty()));
|
||||
}
|
||||
} else { //All files not in dir1 shouldn't have MIME type
|
||||
String errMsg = String.format("File %s (objId=%d) unexpectedly passed by the file filter.", file.getName(), file.getId());
|
||||
assertTrue(errMsg, file.getMIMEType() == null);
|
||||
}
|
||||
}
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
Exceptions.printStackTrace(ex);
|
||||
Assert.fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void runIngestJob(List<Content> datasources) {
|
||||
private void runIngestJob(List<Content> datasources, FilesSet filter) {
|
||||
FileTypeIdModuleFactory factory = new FileTypeIdModuleFactory();
|
||||
IngestModuleIngestJobSettings settings = factory.getDefaultIngestJobSettings();
|
||||
IngestModuleTemplate template = new IngestModuleTemplate(factory, settings);
|
||||
template.setEnabled(true);
|
||||
ArrayList<IngestModuleTemplate> templates = new ArrayList<>();
|
||||
templates.add(template);
|
||||
IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestFileFiltersTest.class.getCanonicalName(), IngestType.FILES_ONLY, templates);
|
||||
IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestFileFiltersTest.class.getCanonicalName(), IngestType.FILES_ONLY, templates, filter);
|
||||
try {
|
||||
List<IngestModuleError> errs = IngestJobRunner.runIngestJob(datasources, ingestJobSettings);
|
||||
assertEquals(0, errs.size());
|
||||
@ -146,4 +177,5 @@ public class IngestFileFiltersTest extends TestCase {
|
||||
Assert.fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -23,80 +23,89 @@ import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
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.Image;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/*
|
||||
* A runnable that adds a raw data source to a case database.
|
||||
* A runnable that adds a memory image data source to a case database.
|
||||
*/
|
||||
final class AddMemoryImageTask implements Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AddMemoryImageTask.class.getName());
|
||||
private final static Logger logger = Logger.getLogger(AddMemoryImageTask.class.getName());
|
||||
private final String deviceId;
|
||||
private final String imageFilePath;
|
||||
private final String memoryImagePath;
|
||||
private final String timeZone;
|
||||
private final List<String> pluginsToRun;
|
||||
private final DataSourceProcessorProgressMonitor progressMonitor;
|
||||
private final DataSourceProcessorCallback callback;
|
||||
private VolatilityProcessor volatilityProcessor = null;
|
||||
private boolean isCancelled = false;
|
||||
private volatile VolatilityProcessor volatilityProcessor;
|
||||
private volatile boolean isCancelled;
|
||||
|
||||
/**
|
||||
* Constructs a runnable that adds a raw data source to a case database.
|
||||
* Constructs a runnable that adds a memory image 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
|
||||
* @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 memoryImagePath Path to the memory image file.
|
||||
* @param pluginsToRun The Volatility plugins to run.
|
||||
* @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 progressMonitor Progress monitor for reporting progressMonitor
|
||||
* during processing.
|
||||
* @param callback Callback to call when processing is done.
|
||||
*/
|
||||
AddMemoryImageTask(String deviceId, String imageFilePath, List<String> PluginsToRun, String timeZone, long chunkSize, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||
AddMemoryImageTask(String deviceId, String memoryImagePath, List<String> pluginsToRun, String timeZone, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||
this.deviceId = deviceId;
|
||||
this.imageFilePath = imageFilePath;
|
||||
this.pluginsToRun = PluginsToRun;
|
||||
this.memoryImagePath = memoryImagePath;
|
||||
this.pluginsToRun = pluginsToRun;
|
||||
this.timeZone = timeZone;
|
||||
this.callback = callback;
|
||||
this.progressMonitor = progressMonitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a raw data source to a case database.
|
||||
* Adds a memory image data source to a case database.
|
||||
*/
|
||||
@Messages({
|
||||
"# {0} - exception message",
|
||||
"AddMemoryImageTask_errorMessage_criticalException= Critical error: {0}",
|
||||
})
|
||||
@Override
|
||||
public void run() {
|
||||
if (isCancelled) {
|
||||
return;
|
||||
}
|
||||
progressMonitor.setIndeterminate(true);
|
||||
progressMonitor.setProgress(0);
|
||||
List<Content> dataSources = new ArrayList<>();
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
boolean criticalErrorOccurred = false;
|
||||
Image dataSource = addImageToCase(errorMessages);
|
||||
if (dataSource == null) {
|
||||
criticalErrorOccurred = true;
|
||||
}
|
||||
/* call Volatility to process the image */
|
||||
else {
|
||||
if (isCancelled)
|
||||
return;
|
||||
|
||||
volatilityProcessor = new VolatilityProcessor(imageFilePath, dataSource, pluginsToRun, progressMonitor);
|
||||
if (volatilityProcessor.run()) {
|
||||
try {
|
||||
Image dataSource = addImageToCase();
|
||||
dataSources.add(dataSource);
|
||||
volatilityProcessor = new VolatilityProcessor(memoryImagePath, dataSource, pluginsToRun, progressMonitor);
|
||||
volatilityProcessor.run();
|
||||
} catch (NoCurrentCaseException | TskCoreException | VolatilityProcessor.VolatilityProcessorException ex) {
|
||||
criticalErrorOccurred = true;
|
||||
errorMessages.add(Bundle.AddMemoryImageTask_errorMessage_criticalException(ex.getLocalizedMessage()));
|
||||
/*
|
||||
* Log the exception as well as add it to the error messages, to
|
||||
* ensure that the stack trace is not lost.
|
||||
*/
|
||||
logger.log(Level.SEVERE, String.format("Critical error processing memory image data source at %s for device %s", memoryImagePath, deviceId), ex);
|
||||
}
|
||||
errorMessages.addAll(volatilityProcessor.getErrorMessages());
|
||||
}
|
||||
|
||||
progressMonitor.setProgress(100);
|
||||
|
||||
/**
|
||||
@ -110,55 +119,64 @@ final class AddMemoryImageTask implements Runnable {
|
||||
} else {
|
||||
result = DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS;
|
||||
}
|
||||
|
||||
callback.done(result, errorMessages, new ArrayList<>(Arrays.asList(dataSource)));
|
||||
callback.done(result, errorMessages, dataSources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to add the input image to the case.
|
||||
* Attempts to add the input memory image to the case as a data source.
|
||||
*
|
||||
* @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.
|
||||
* @returns Image that was added to DB or null on error
|
||||
* @return The Image object representation of the memeory image file data
|
||||
* source.
|
||||
*
|
||||
* @throws NoCurrentCaseException If there is no current case.
|
||||
* @throws TskCoreException If there is an error adding the data
|
||||
* source to the case database.
|
||||
*/
|
||||
@Messages({"AddMemoryImageTask.progress.add.text=Adding memory image: ",
|
||||
"AddMemoryImageTask.image.critical.error.adding=Critical error adding ",
|
||||
"AddMemoryImageTask.for.device=for device ",
|
||||
"AddMemoryImageTask.image.notExisting=is not existing.",
|
||||
"AddMemoryImageTask.image.noncritical.error.adding=Non-critical error adding "})
|
||||
private Image addImageToCase(List<String> errorMessages) {
|
||||
progressMonitor.setProgressText(Bundle.AddMemoryImageTask_progress_add_text() + imageFilePath);
|
||||
|
||||
SleuthkitCase caseDatabase = Case.getCurrentCase().getSleuthkitCase();
|
||||
caseDatabase.acquireExclusiveLock();
|
||||
|
||||
// verify it exists
|
||||
File imageFile = Paths.get(imageFilePath).toFile();
|
||||
if (!imageFile.exists()) {
|
||||
errorMessages.add(Bundle.AddMemoryImageTask_image_critical_error_adding() + imageFilePath + Bundle.AddMemoryImageTask_for_device()
|
||||
+ deviceId + Bundle.AddMemoryImageTask_image_notExisting());
|
||||
return null;
|
||||
}
|
||||
@Messages({
|
||||
"# {0} - image file path",
|
||||
"AddMemoryImageTask_progressMessage_addingImageFile= Adding memory image {0}",
|
||||
"# {0} - image file path",
|
||||
"# {1} - device id",
|
||||
"AddMemoryImageTask_exceptionMessage_noImageFile= Memory image file {0} for device {1} does not exist"
|
||||
})
|
||||
private Image addImageToCase() throws NoCurrentCaseException, TskCoreException {
|
||||
progressMonitor.setProgressText(Bundle.AddMemoryImageTask_progressMessage_addingImageFile( memoryImagePath));
|
||||
|
||||
SleuthkitCase caseDatabase = Case.getOpenCase().getSleuthkitCase();
|
||||
caseDatabase.acquireSingleUserCaseWriteLock();
|
||||
try {
|
||||
// add it to the DB
|
||||
List<String> imageFilePaths = new ArrayList<>();
|
||||
imageFilePaths.add(imageFilePath);
|
||||
Image dataSource = caseDatabase.addImageInfo(0, imageFilePaths, timeZone); //TODO: change hard coded deviceId.
|
||||
/*
|
||||
* Verify the memory image file exists.
|
||||
*/
|
||||
File imageFile = Paths.get(memoryImagePath).toFile();
|
||||
if (!imageFile.exists()) {
|
||||
throw new TskCoreException(Bundle.AddMemoryImageTask_exceptionMessage_noImageFile(memoryImagePath, deviceId));
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the data source.
|
||||
*
|
||||
* NOTE: The object id for device passed to
|
||||
* SleuthkitCase.addImageInfo is hard-coded to zero for now. This
|
||||
* will need to be changed when a Device abstraction is added to the
|
||||
* SleuthKit data model.
|
||||
*/
|
||||
Image dataSource = caseDatabase.addImageInfo(0, new ArrayList<>(Arrays.asList(memoryImagePath)), timeZone);
|
||||
return dataSource;
|
||||
} catch (TskCoreException ex) {
|
||||
errorMessages.add(Bundle.AddMemoryImageTask_image_critical_error_adding() + imageFilePath + Bundle.AddMemoryImageTask_for_device() + deviceId + ":" + ex.getLocalizedMessage());
|
||||
return null;
|
||||
|
||||
} finally {
|
||||
caseDatabase.releaseExclusiveLock();
|
||||
caseDatabase.releaseSingleUserCaseWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests cancellation of this task by setting a cancelled flag.
|
||||
*/
|
||||
void cancelTask() {
|
||||
isCancelled = true;
|
||||
if (volatilityProcessor != null) {
|
||||
volatilityProcessor.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -37,11 +37,13 @@ import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.TableColumn;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.PathValidator;
|
||||
|
||||
final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
||||
|
||||
private static final long serialVersionUID = 1L; //default
|
||||
private final String PROP_LASTINPUT_PATH = "LBL_LastInputFile_PATH";
|
||||
private final JFileChooser fc = new JFileChooser();
|
||||
@ -153,16 +155,16 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
||||
|
||||
for (String plugin : pluginList) {
|
||||
PluginListNames.add(plugin);
|
||||
if (allEnabled)
|
||||
if (allEnabled) {
|
||||
pluginListStates.put(plugin, true);
|
||||
else
|
||||
} else {
|
||||
pluginListStates.put(plugin, pluginMap.containsKey(plugin));
|
||||
}
|
||||
}
|
||||
tableModel.fireTableDataChanged();
|
||||
//this.tableModel = pluginsToRun.getModel();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -374,11 +376,19 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
||||
*
|
||||
* @param path Absolute path to the selected data source
|
||||
*/
|
||||
@Messages({"MemoryDSInputPanel.error.text=Path to multi-user data source is on \"C:\" drive"})
|
||||
@Messages({
|
||||
"MemoryDSInputPanel_errorMsg_noOpenCase=No open case",
|
||||
"MemoryDSInputPanel_errorMsg_dataSourcePathOnCdrive=Path to multi-user data source is on \"C:\" drive"
|
||||
})
|
||||
private void warnIfPathIsInvalid(String path) {
|
||||
if (!PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) {
|
||||
try {
|
||||
if (!PathValidator.isValid(path, Case.getOpenCase().getCaseType())) {
|
||||
errorLabel.setVisible(true);
|
||||
errorLabel.setText(Bundle.MemoryDSInputPanel_error_text());
|
||||
errorLabel.setText(Bundle.MemoryDSInputPanel_errorMsg_dataSourcePathOnCdrive());
|
||||
}
|
||||
} catch (NoCurrentCaseException unused) {
|
||||
errorLabel.setVisible(true);
|
||||
errorLabel.setText(Bundle.MemoryDSInputPanel_errorMsg_dataSourcePathOnCdrive());
|
||||
}
|
||||
}
|
||||
|
||||
@ -470,5 +480,4 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -28,21 +28,21 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
|
||||
/**
|
||||
* A MEmory 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.
|
||||
* A memory image 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 MemoryDSProcessor implements DataSourceProcessor {
|
||||
|
||||
private final MemoryDSInputPanel configPanel;
|
||||
private AddMemoryImageTask addImageTask = null;
|
||||
private AddMemoryImageTask addImageTask;
|
||||
|
||||
/*
|
||||
* Constructs a Memory data source processor that implements the
|
||||
* Constructs a memory 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
|
||||
* the Add Data source wizard. It also provides a run method overload to
|
||||
* allow it to be used independently of the wizard.
|
||||
*/
|
||||
public MemoryDSProcessor() {
|
||||
@ -117,37 +117,40 @@ public class MemoryDSProcessor implements DataSourceProcessor {
|
||||
@Override
|
||||
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||
configPanel.storeSettings();
|
||||
run(UUID.randomUUID().toString(), configPanel.getImageFilePath(), configPanel.getPluginsToRun(), configPanel.getTimeZone(), 0, progressMonitor, callback);
|
||||
run(UUID.randomUUID().toString(), configPanel.getImageFilePath(), configPanel.getPluginsToRun(), configPanel.getTimeZone(), progressMonitor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a "memory" 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.
|
||||
* Adds a memory image 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 imageFilePath Path to the image file.
|
||||
* @param timeZone The time zone to use when processing dates
|
||||
* and times for the image, obtained from
|
||||
* associated with the data source that is intended
|
||||
* to be unique across multiple cases (e.g., a UUID).
|
||||
* @param memoryImagePath Path to the memory image file.
|
||||
* @param pluginsToRun The Volatility plugins to run.
|
||||
* @param timeZone The time zone to use when processing dates and
|
||||
* times for the image, obtained from
|
||||
* java.util.TimeZone.getID.
|
||||
* @param chunkSize The maximum size of each chunk of the raw
|
||||
* data source as it is divided up into virtual
|
||||
* unallocated space files.
|
||||
* @param progressMonitor Progress monitor for reporting progress
|
||||
* during processing.
|
||||
* @param progressMonitor Progress monitor for reporting progress during
|
||||
* processing.
|
||||
* @param callback Callback to call when processing is done.
|
||||
*/
|
||||
private void run(String deviceId, String imageFilePath, List<String> pluginsToRun, String timeZone, long chunkSize, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||
addImageTask = new AddMemoryImageTask(deviceId, imageFilePath, pluginsToRun, timeZone, 0, progressMonitor, callback);
|
||||
private void run(String deviceId, String memoryImagePath, List<String> pluginsToRun, String timeZone, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||
addImageTask = new AddMemoryImageTask(deviceId, memoryImagePath, pluginsToRun, timeZone, progressMonitor, callback);
|
||||
new Thread(addImageTask).start();
|
||||
//new Thread(new AddLocalFilesTask(deviceId, rootVirtualDirectoryName, localFilePaths, progressMonitor, callback)).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests cancellation of the background task that adds a data source to
|
||||
* the case database, after the task is started using the run method. This
|
||||
* is a "best effort" cancellation, with no guarantees that the case
|
||||
* database will be unchanged. If cancellation succeeded, the list of new
|
||||
* data sources returned by the background task will be empty.
|
||||
*/
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (addImageTask != null) {
|
||||
@ -165,4 +168,3 @@ public class MemoryDSProcessor implements DataSourceProcessor {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -376,12 +376,12 @@ public class ExtractedContentViewer implements DataContentViewer {
|
||||
if (artifact == null) {
|
||||
return 4;
|
||||
} else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
||||
return 6;
|
||||
return 7;
|
||||
} else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
||||
try {
|
||||
BlackboardAttribute attribute = artifact.getAttribute(TSK_ACCOUNT_TYPE);
|
||||
if (attribute != null && Account.Type.CREDIT_CARD.getTypeName().equals(attribute.getValueString())) {
|
||||
return 6;
|
||||
return 7;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
|
@ -645,18 +645,18 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
*/
|
||||
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, t -> {
|
||||
|
||||
if( ! attributeMap.containsKey(type)) {
|
||||
String value = matcher.group(groupName);
|
||||
if (attrType.equals(ATTRIBUTE_TYPE.TSK_CARD_NUMBER)) {
|
||||
attributeMap.put(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD),
|
||||
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, value));
|
||||
value = CharMatcher.anyOf(" -").removeFrom(value);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
return new BlackboardAttribute(attrType, MODULE_NAME, value);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
attributeMap.put(type, new BlackboardAttribute(attrType, MODULE_NAME, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,24 +175,24 @@ class ExtractRegistry extends Extract {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
for (AbstractFile regFile : allRegistryFiles) {
|
||||
String regFileName = regFile.getName();
|
||||
long regFileId = regFile.getId();
|
||||
String regFileNameLocal = RAImageIngestModule.getRATempPath(currentCase, "reg") + File.separator + regFileName;
|
||||
String outputPathBase = RAImageIngestModule.getRAOutputPath(currentCase, "reg") + File.separator + regFileName + "-regripper-" + Integer.toString(j++); //NON-NLS
|
||||
String outputPathBase = RAImageIngestModule.getRAOutputPath(currentCase, "reg") + File.separator + regFileName + "-regripper-" + Long.toString(regFileId); //NON-NLS
|
||||
File regFileNameLocalFile = new File(regFileNameLocal);
|
||||
try {
|
||||
ContentUtils.writeToFile(regFile, regFileNameLocalFile, context::dataSourceIngestIsCancelled);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error reading registry file '%s' (id=%d).",
|
||||
regFile.getName(), regFile.getId()), ex); //NON-NLS
|
||||
regFile.getName(), regFileId), ex); //NON-NLS
|
||||
this.addErrorMessage(
|
||||
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.errMsg.errWritingTemp",
|
||||
this.getName(), regFileName));
|
||||
continue;
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error writing temp registry file '%s' for registry file '%s' (id=%d).",
|
||||
regFileNameLocal, regFile.getName(), regFile.getId()), ex); //NON-NLS
|
||||
regFileNameLocal, regFile.getName(), regFileId), ex); //NON-NLS
|
||||
this.addErrorMessage(
|
||||
NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.errMsg.errWritingTemp",
|
||||
this.getName(), regFileName));
|
||||
@ -205,7 +205,7 @@ class ExtractRegistry extends Extract {
|
||||
|
||||
try {
|
||||
if (logFile != null) {
|
||||
logFile.write(Integer.toString(j - 1) + "\t" + regFile.getUniquePath() + "\n");
|
||||
logFile.write(Long.toString(regFileId) + "\t" + regFile.getUniquePath() + "\n");
|
||||
}
|
||||
} catch (TskCoreException | IOException ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
|
Loading…
x
Reference in New Issue
Block a user