mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge in develop branch
This commit is contained in:
commit
8e4d7e2c4f
@ -20,12 +20,14 @@ package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.LocalFilesDataSource;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
@ -37,6 +39,7 @@ import org.sleuthkit.datamodel.TskDataException;
|
||||
*/
|
||||
class AddLocalFilesTask implements Runnable {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(AddLocalFilesTask.class.getName());
|
||||
private final String deviceId;
|
||||
private final String rootVirtualDirectoryName;
|
||||
private final List<String> localFilePaths;
|
||||
@ -89,6 +92,7 @@ class AddLocalFilesTask implements Runnable {
|
||||
newDataSources.add(newDataSource.getRootDirectory());
|
||||
} catch (TskDataException | TskCoreException ex) {
|
||||
errors.add(ex.getMessage());
|
||||
LOGGER.log(Level.SEVERE, String.format("Failed to add datasource: %s", ex.getMessage()), ex);
|
||||
} finally {
|
||||
DataSourceProcessorCallback.DataSourceProcessorResult result;
|
||||
if (!errors.isEmpty()) {
|
||||
|
@ -377,7 +377,9 @@ public class Case {
|
||||
*
|
||||
* @param eventNames The events the subscriber is interested in.
|
||||
* @param subscriber The subscriber (PropertyChangeListener) to add.
|
||||
* @deprecated Use addEventTypeSubscriber instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addEventSubscriber(Set<String> eventNames, PropertyChangeListener subscriber) {
|
||||
eventPublisher.addSubscriber(eventNames, subscriber);
|
||||
}
|
||||
@ -385,9 +387,23 @@ public class Case {
|
||||
/**
|
||||
* Adds a subscriber to specific case events.
|
||||
*
|
||||
* @param eventName The event the subscriber is interested in.
|
||||
* @param eventTypes The events the subscriber is interested in.
|
||||
* @param subscriber The subscriber (PropertyChangeListener) to add.
|
||||
*/
|
||||
public static void addEventTypeSubscriber(Set<Events> eventTypes, PropertyChangeListener subscriber) {
|
||||
eventTypes.forEach((Events event) -> {
|
||||
eventPublisher.addSubscriber(event.toString(), subscriber);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a subscriber to specific case events.
|
||||
*
|
||||
* @param eventName The event the subscriber is interested in.
|
||||
* @param subscriber The subscriber (PropertyChangeListener) to add.
|
||||
* @deprecated Use addEventTypeSubscriber instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addEventSubscriber(String eventName, PropertyChangeListener subscriber) {
|
||||
eventPublisher.addSubscriber(eventName, subscriber);
|
||||
}
|
||||
@ -412,6 +428,18 @@ public class Case {
|
||||
eventPublisher.removeSubscriber(eventNames, subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a subscriber to specific case events.
|
||||
*
|
||||
* @param eventTypes The events the subscriber is no longer interested in.
|
||||
* @param subscriber The subscriber (PropertyChangeListener) to remove.
|
||||
*/
|
||||
public static void removeEventTypeSubscriber(Set<Events> eventTypes, PropertyChangeListener subscriber) {
|
||||
eventTypes.forEach((Events event) -> {
|
||||
eventPublisher.removeSubscriber(event.toString(), subscriber);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a case display name is valid, i.e., does not include any
|
||||
* characters that cannot be used in file names.
|
||||
|
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.EnumSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
@ -49,7 +50,7 @@ final class CaseDeleteAction extends CallableSystemAction {
|
||||
CaseDeleteAction() {
|
||||
putValue(Action.NAME, NbBundle.getMessage(CaseDeleteAction.class, "CTL_CaseDeleteAction"));
|
||||
this.setEnabled(false);
|
||||
Case.addEventSubscriber(Case.Events.CURRENT_CASE.toString(), (PropertyChangeEvent evt) -> {
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||
setEnabled(null != evt.getNewValue() && UserPreferences.getMode() != UserPreferences.SelectedMode.REVIEW);
|
||||
});
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import java.awt.Dimension;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.EnumSet;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.SwingUtilities;
|
||||
@ -42,7 +43,7 @@ final class CasePropertiesAction extends CallableSystemAction {
|
||||
CasePropertiesAction() {
|
||||
putValue(Action.NAME, NbBundle.getMessage(CasePropertiesAction.class, "CTL_CasePropertiesAction"));
|
||||
this.setEnabled(false);
|
||||
Case.addEventSubscriber(Case.Events.CURRENT_CASE.toString(), (PropertyChangeEvent evt) -> {
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||
setEnabled(null != evt.getNewValue());
|
||||
});
|
||||
}
|
||||
|
@ -24,9 +24,8 @@ import java.beans.PropertyChangeListener;
|
||||
import java.io.Serializable;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -57,7 +56,8 @@ final class CollaborationMonitor {
|
||||
|
||||
private static final String EVENT_CHANNEL_NAME = "%s-Collaboration-Monitor-Events"; //NON-NLS
|
||||
private static final String COLLABORATION_MONITOR_EVENT = "COLLABORATION_MONITOR_EVENT"; //NON-NLS
|
||||
private static final Set<String> CASE_EVENTS_OF_INTEREST = new HashSet<>(Arrays.asList(new String[]{Case.Events.ADDING_DATA_SOURCE.toString(), Case.Events.DATA_SOURCE_ADDED.toString(), Case.Events.ADDING_DATA_SOURCE_FAILED.toString()}));
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.ADDING_DATA_SOURCE,
|
||||
Case.Events.DATA_SOURCE_ADDED, Case.Events.ADDING_DATA_SOURCE_FAILED);
|
||||
private static final int NUMBER_OF_PERIODIC_TASK_THREADS = 2;
|
||||
private static final String PERIODIC_TASK_THREAD_NAME = "collab-monitor-periodic-tasks-%d"; //NON-NLS
|
||||
private static final long HEARTBEAT_INTERVAL_MINUTES = 1;
|
||||
@ -113,7 +113,7 @@ final class CollaborationMonitor {
|
||||
*/
|
||||
localTasksManager = new LocalTasksManager();
|
||||
IngestManager.getInstance().addIngestJobEventListener(localTasksManager);
|
||||
Case.addEventSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager);
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager);
|
||||
|
||||
/**
|
||||
* Start periodic tasks that:
|
||||
@ -141,7 +141,7 @@ final class CollaborationMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
Case.removeEventSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager);
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager);
|
||||
IngestManager.getInstance().removeIngestJobEventListener(localTasksManager);
|
||||
|
||||
if (null != eventPublisher) {
|
||||
|
@ -1524,9 +1524,11 @@ public abstract class AbstractSqlEamDb implements EamDb {
|
||||
@Override
|
||||
public void bulkInsertReferenceTypeEntries(Set<EamGlobalFileInstance> globalInstances, EamArtifact.Type contentType) throws EamDbException {
|
||||
Connection conn = connect();
|
||||
|
||||
|
||||
PreparedStatement bulkPs = null;
|
||||
try {
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
// FUTURE: have a separate global_files table for each Type.
|
||||
String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
|
||||
+ getConflictClause();
|
||||
@ -1542,8 +1544,14 @@ public abstract class AbstractSqlEamDb implements EamDb {
|
||||
}
|
||||
|
||||
bulkPs.executeBatch();
|
||||
conn.commit();
|
||||
} catch (SQLException ex) {
|
||||
throw new EamDbException("Error inserting bulk artifacts.", ex); // NON-NLS
|
||||
try{
|
||||
conn.rollback();
|
||||
} catch (SQLException ex2){
|
||||
// We're alredy in an error state
|
||||
}
|
||||
throw new EamDbException("Error inserting bulk artifacts.", ex); // NON-NLS
|
||||
} finally {
|
||||
EamDbUtil.closePreparedStatement(bulkPs);
|
||||
EamDbUtil.closeConnection(conn);
|
||||
|
@ -36,8 +36,11 @@ public interface EamDb {
|
||||
* @throws EamDbException
|
||||
*/
|
||||
static EamDb getInstance() throws EamDbException {
|
||||
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
|
||||
|
||||
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.DISABLED;
|
||||
if (EamDbUtil.useCentralRepo()) {
|
||||
selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
|
||||
}
|
||||
switch (selectedPlatform) {
|
||||
case POSTGRESQL:
|
||||
return PostgresEamDb.getInstance();
|
||||
@ -86,7 +89,8 @@ public interface EamDb {
|
||||
* @return Is the database enabled
|
||||
*/
|
||||
static boolean isEnabled() {
|
||||
return EamDbPlatformEnum.getSelectedPlatform() != EamDbPlatformEnum.DISABLED;
|
||||
return EamDbUtil.useCentralRepo()
|
||||
&& EamDbPlatformEnum.getSelectedPlatform() != EamDbPlatformEnum.DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,7 +3,6 @@
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
package org.sleuthkit.autopsy.centralrepository.datamodel;
|
||||
|
||||
import java.sql.Connection;
|
||||
@ -15,13 +14,17 @@ import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDb.SCHEMA_VERSION;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class EamDbUtil {
|
||||
|
||||
private final static Logger LOGGER = Logger.getLogger(EamDbUtil.class.getName());
|
||||
|
||||
private static final String CENTRAL_REPO_NAME = "CentralRepository";
|
||||
private static final String CENTRAL_REPO_USE_KEY = "db.useCentralRepo";
|
||||
|
||||
/**
|
||||
* Close the prepared statement.
|
||||
*
|
||||
@ -72,11 +75,12 @@ public class EamDbUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert the default correlation types into the database.
|
||||
*
|
||||
*
|
||||
* @param conn Open connection to use.
|
||||
*
|
||||
* @return true on success, else false
|
||||
*/
|
||||
public static boolean insertDefaultCorrelationTypes(Connection conn) {
|
||||
@ -104,7 +108,7 @@ public class EamDbUtil {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store the schema version into the db_info table.
|
||||
*
|
||||
@ -112,6 +116,7 @@ public class EamDbUtil {
|
||||
* loaded.
|
||||
*
|
||||
* @param conn Open connection to use.
|
||||
*
|
||||
* @return true on success, else false
|
||||
*/
|
||||
public static boolean insertSchemaVersion(Connection conn) {
|
||||
@ -133,14 +138,14 @@ public class EamDbUtil {
|
||||
|
||||
/**
|
||||
* Query to see if the SCHEMA_VERSION is set in the db.
|
||||
*
|
||||
*
|
||||
* @return true if set, else false.
|
||||
*/
|
||||
public static boolean schemaVersionIsSet(Connection conn) {
|
||||
if (null == conn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
Statement tester = conn.createStatement();
|
||||
@ -157,17 +162,38 @@ public class EamDbUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the current settings and the validation query
|
||||
* to test the connection to the database.
|
||||
*
|
||||
/**
|
||||
* If the Central Repos use has been enabled.
|
||||
*
|
||||
* @return true if the Central Repo may be configured, false if it should
|
||||
* not be able to be
|
||||
*/
|
||||
public static boolean useCentralRepo() {
|
||||
return Boolean.parseBoolean(ModuleSettings.getConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the setting for whether the Central Repo should be able to be
|
||||
* configured.
|
||||
*
|
||||
* @param centralRepoCheckBoxIsSelected - true if the central repo can be
|
||||
* used
|
||||
*/
|
||||
public static void setUseCentralRepo(boolean centralRepoCheckBoxIsSelected) {
|
||||
ModuleSettings.setConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY, Boolean.toString(centralRepoCheckBoxIsSelected));
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the current settings and the validation query to test the connection
|
||||
* to the database.
|
||||
*
|
||||
* @return true if successfull query execution, else false.
|
||||
*/
|
||||
public static boolean executeValidationQuery(Connection conn, String validationQuery) {
|
||||
if (null == conn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
Statement tester = conn.createStatement();
|
||||
@ -183,22 +209,23 @@ public class EamDbUtil {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Conver thte Type's DbTableName string to the *_instances table name.
|
||||
*
|
||||
*
|
||||
* @param type Correlation Type
|
||||
* @return Instance table name for this Type.
|
||||
*
|
||||
* @return Instance table name for this Type.
|
||||
*/
|
||||
public static String correlationTypeToInstanceTableName(EamArtifact.Type type) {
|
||||
return type.getDbTableName() + "_instances";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the Type's DbTableName string to the reference_* table name.
|
||||
*
|
||||
*
|
||||
* @param type Correlation Type
|
||||
*
|
||||
* @return Reference table name for this Type.
|
||||
*/
|
||||
public static String correlationTypeToReferenceTableName(EamArtifact.Type type) {
|
||||
|
@ -72,8 +72,10 @@ public class PostgresEamDb extends AbstractSqlEamDb {
|
||||
public void shutdownConnections() throws EamDbException {
|
||||
try {
|
||||
synchronized(this) {
|
||||
connectionPool.close();
|
||||
connectionPool = null; // force it to be re-created on next connect()
|
||||
if(connectionPool != null){
|
||||
connectionPool.close();
|
||||
connectionPool = null; // force it to be re-created on next connect()
|
||||
}
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
throw new EamDbException("Failed to close existing database connections.", ex); // NON-NLS
|
||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.centralrepository.datamodel;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
@ -93,7 +94,7 @@ public final class SqliteEamDbSettings {
|
||||
if (badTagsStr == null) {
|
||||
badTagsStr = DEFAULT_BAD_TAGS;
|
||||
}
|
||||
if(badTagsStr.isEmpty()){
|
||||
if (badTagsStr.isEmpty()) {
|
||||
badTags = new ArrayList<>();
|
||||
} else {
|
||||
badTags = new ArrayList<>(Arrays.asList(badTagsStr.split(",")));
|
||||
@ -111,13 +112,13 @@ public final class SqliteEamDbSettings {
|
||||
|
||||
/**
|
||||
* Verify that the db directory path exists.
|
||||
*
|
||||
*
|
||||
* @return true if exists, else false
|
||||
*/
|
||||
public boolean dbDirectoryExists() {
|
||||
// Ensure dbDirectory is a valid directory
|
||||
File dbDir = new File(getDbDirectory());
|
||||
|
||||
|
||||
if (!dbDir.exists()) {
|
||||
return false;
|
||||
} else if (!dbDir.isDirectory()) {
|
||||
@ -130,7 +131,7 @@ public final class SqliteEamDbSettings {
|
||||
|
||||
/**
|
||||
* Create the db directory if it does not exist.
|
||||
*
|
||||
*
|
||||
* @return true is successfully created or already exists, else false
|
||||
*/
|
||||
public boolean createDbDirectory() {
|
||||
@ -139,7 +140,7 @@ public final class SqliteEamDbSettings {
|
||||
File dbDir = new File(getDbDirectory());
|
||||
Files.createDirectories(dbDir.toPath());
|
||||
LOGGER.log(Level.INFO, "sqlite directory did not exist, created it at {0}.", getDbDirectory()); // NON-NLS
|
||||
} catch (IOException ex) {
|
||||
} catch (IOException | InvalidPathException | SecurityException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to create sqlite database directory.", ex); // NON-NLS
|
||||
return false;
|
||||
}
|
||||
@ -162,10 +163,11 @@ public final class SqliteEamDbSettings {
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the current settings to get an ephemeral client connection for testing.
|
||||
*
|
||||
* Use the current settings to get an ephemeral client connection for
|
||||
* testing.
|
||||
*
|
||||
* If the directory path does not exist, it will return null.
|
||||
*
|
||||
*
|
||||
* @return Connection or null.
|
||||
*/
|
||||
private Connection getEphemeralConnection() {
|
||||
@ -186,9 +188,9 @@ public final class SqliteEamDbSettings {
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the current settings and the validation query
|
||||
* to test the connection to the database.
|
||||
*
|
||||
* Use the current settings and the validation query to test the connection
|
||||
* to the database.
|
||||
*
|
||||
* @return true if successfull connection, else false.
|
||||
*/
|
||||
public boolean verifyConnection() {
|
||||
@ -196,16 +198,16 @@ public final class SqliteEamDbSettings {
|
||||
if (null == conn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
boolean result = EamDbUtil.executeValidationQuery(conn, VALIDATION_QUERY);
|
||||
EamDbUtil.closeConnection(conn);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the current settings and the schema version query
|
||||
* to test the database schema.
|
||||
*
|
||||
* Use the current settings and the schema version query to test the
|
||||
* database schema.
|
||||
*
|
||||
* @return true if successfull connection, else false.
|
||||
*/
|
||||
public boolean verifyDatabaseSchema() {
|
||||
@ -247,7 +249,6 @@ public final class SqliteEamDbSettings {
|
||||
|
||||
// NOTE: The organizations will only have a small number of rows, so
|
||||
// an index is probably not worthwhile.
|
||||
|
||||
StringBuilder createCasesTable = new StringBuilder();
|
||||
createCasesTable.append("CREATE TABLE IF NOT EXISTS cases (");
|
||||
createCasesTable.append("id integer primary key autoincrement NOT NULL,");
|
||||
@ -346,7 +347,6 @@ public final class SqliteEamDbSettings {
|
||||
|
||||
// NOTE: the db_info table currenly only has 1 row, so having an index
|
||||
// provides no benefit.
|
||||
|
||||
Connection conn = null;
|
||||
try {
|
||||
conn = getEphemeralConnection();
|
||||
@ -385,7 +385,7 @@ public final class SqliteEamDbSettings {
|
||||
for (EamArtifact.Type type : DEFAULT_CORRELATION_TYPES) {
|
||||
reference_type_dbname = EamDbUtil.correlationTypeToReferenceTableName(type);
|
||||
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
|
||||
|
||||
|
||||
stmt.execute(String.format(createArtifactInstancesTableTemplate.toString(), instance_type_dbname, instance_type_dbname));
|
||||
stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
|
||||
stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
|
||||
@ -397,7 +397,7 @@ public final class SqliteEamDbSettings {
|
||||
stmt.execute(String.format(createReferenceTypesTableTemplate.toString(), reference_type_dbname, reference_type_dbname));
|
||||
stmt.execute(String.format(referenceTypesIdx1, reference_type_dbname, reference_type_dbname));
|
||||
stmt.execute(String.format(referenceTypesIdx2, reference_type_dbname, reference_type_dbname));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS
|
||||
@ -422,7 +422,7 @@ public final class SqliteEamDbSettings {
|
||||
EamDbUtil.closeConnection(conn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public boolean isChanged() {
|
||||
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbName"); // NON-NLS
|
||||
String dbDirectoryString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbDirectory"); // NON-NLS
|
||||
|
@ -13,7 +13,7 @@ EamSqliteSettingsDialog.bnCancel.text=Cancel
|
||||
EamSqliteSettingsDialog.lbTestDatabase.text=
|
||||
EamSqliteSettingsDialog.bnTestDatabase.text=Test Connection
|
||||
EamSqliteSettingsDialog.lbTestDatabaseWarning.text=
|
||||
EamSqliteSettingsDialog.bnDatabasePathFileOpen.text=Open...
|
||||
EamSqliteSettingsDialog.bnDatabasePathFileOpen.text=Browse...
|
||||
EamSqliteSettingsDialog.tfDatabasePath.toolTipText=Filename and path to store SQLite db file
|
||||
EamSqliteSettingsDialog.tfDatabasePath.text=
|
||||
EamSqliteSettingsDialog.lbDatabasePath.text=Database Path :
|
||||
@ -52,24 +52,16 @@ ManageTagsDialog.cancelButton.text=Cancel
|
||||
ManageArtifactTypesDialog.taInstructionsMsg.text=Enable one or more correlation properties to use for correlation during ingest. Note, these properties are global and impact all users of the central repository.
|
||||
EamSqliteSettingsDialog.bnOk.text=OK
|
||||
EamPostgresSettingsDialog.bnSave.text=Save
|
||||
EamDbSettingsDialog.pnDatabaseConnectionSettings.border.title=Database Settings
|
||||
EamDbSettingsDialog.rdioBnPostgreSQL.text=PostgreSQL
|
||||
EamDbSettingsDialog.rdioBnSQLite.text=SQLite
|
||||
EamDbSettingsDialog.bnDatabasePathFileOpen.text=Open...
|
||||
EamDbSettingsDialog.bnDatabasePathFileOpen.text=Browse...
|
||||
EamDbSettingsDialog.tfDatabasePath.toolTipText=Filename and path to store SQLite db file
|
||||
EamDbSettingsDialog.tfDatabasePath.text=
|
||||
EamDbSettingsDialog.lbDatabasePath.text=Database Path :
|
||||
EamDbSettingsDialog.rdioBnDisabled.text=Disabled
|
||||
EamDbSettingsDialog.bnCancel.text=Cancel
|
||||
EamDbSettingsDialog.bnOk.text=OK
|
||||
EamDbSettingsDialog.bnTest.text=Test
|
||||
EamDbSettingsDialog.lbHostName.text=Host Name / IP :
|
||||
EamDbSettingsDialog.lbDatabaseName.text=Database name :
|
||||
EamDbSettingsDialog.lbUserPassword.text=User Password :
|
||||
EamDbSettingsDialog.lbUserName.text=User Name :
|
||||
EamDbSettingsDialog.lbPort.text=Port :
|
||||
EamDbSettingsDialog.bnCreateDb.text=Create
|
||||
EamDbSettingsDialog.pnSetupGuidance.border.title=Setup Guidance
|
||||
GlobalSettingsPanel.pnDatabaseConfiguration.title=Database Configuration
|
||||
GlobalSettingsPanel.lbDbPlatformTypeLabel.text=Type:
|
||||
GlobalSettingsPanel.lbDbNameLabel.text=Name:
|
||||
|
@ -29,12 +29,11 @@
|
||||
<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="pnSetupGuidance" max="32767" attributes="0"/>
|
||||
<Component id="pnDatabaseConnectionSettings" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="pnButtons" alignment="1" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="pnButtons" max="32767" attributes="0"/>
|
||||
<Component id="pnSQLiteSettings" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@ -43,303 +42,22 @@
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pnSetupGuidance" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
<Component id="pnSQLiteSettings" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="pnDatabaseConnectionSettings" min="-2" pref="348" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pnButtons" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="pnDatabaseConnectionSettings">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Database Settings">
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.pnDatabaseConnectionSettings.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<Font PropertyName="font" name="Tahoma" size="12" style="0"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="rdioBnPostgreSQL" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="rdioBnSQLite" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="rdioBnDisabled" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="pnSQLiteSettings" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="pnPostgreSQLSettings" alignment="1" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="rdioBnDisabled" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
|
||||
<Component id="rdioBnSQLite" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pnSQLiteSettings" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
|
||||
<Component id="rdioBnPostgreSQL" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pnPostgreSQLSettings" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="329" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="pnSQLiteSettings">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<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="lbDatabasePath" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="tfDatabasePath" min="-2" pref="343" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="bnDatabasePathFileOpen" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbDatabasePath" alignment="3" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<Component id="tfDatabasePath" alignment="3" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<Component id="bnDatabasePathFileOpen" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="lbDatabasePath">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbDatabasePath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tfDatabasePath">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.tfDatabasePath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.tfDatabasePath.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="tfDatabasePathFocusLost"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnDatabasePathFileOpen">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.bnDatabasePathFileOpen.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnDatabasePathFileOpenActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="pnPostgreSQLSettings">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lbHostName" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbPort" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbDatabaseName" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbUserName" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbUserPassword" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="tbDbUsername" alignment="0" pref="439" max="32767" attributes="0"/>
|
||||
<Component id="tbDbName" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="tbDbPort" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="tbDbHostname" max="32767" attributes="0"/>
|
||||
<Component id="jpDbPassword" max="32767" attributes="0"/>
|
||||
</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">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="tbDbHostname" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbHostName" alignment="1" min="-2" pref="22" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="tbDbPort" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="lbPort" alignment="0" min="-2" pref="20" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="tbDbName" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="lbDatabaseName" alignment="0" min="-2" pref="20" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="tbDbUsername" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="lbUserName" alignment="0" min="-2" pref="20" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbUserPassword" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
|
||||
<Component id="jpDbPassword" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="19" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="lbHostName">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbHostName.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbPort">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbPort.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbUserName">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbUserName.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbUserPassword">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbUserPassword.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbDatabaseName">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbDatabaseName.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbDbHostname">
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbDbPort">
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbDbName">
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbDbUsername">
|
||||
</Component>
|
||||
<Component class="javax.swing.JPasswordField" name="jpDbPassword">
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JRadioButton" name="rdioBnSQLite">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.rdioBnSQLite.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="rdioBnSQLiteActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="rdioBnPostgreSQL">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.rdioBnPostgreSQL.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="rdioBnPostgreSQLActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="rdioBnDisabled">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.rdioBnDisabled.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="rdioBnDisabledActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="pnButtons">
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="bnTest" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="lbTestIcon" min="-2" pref="20" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="bnCreateDb" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="lbCreateIcon" min="-2" pref="21" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="bnOk" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="11" max="-2" attributes="0"/>
|
||||
@ -352,20 +70,11 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lbCreateIcon" max="32767" attributes="0"/>
|
||||
<Component id="lbTestIcon" alignment="1" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="bnOk" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="bnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="bnTest" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="bnCreateDb" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="bnOk" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="bnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -391,40 +100,13 @@
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnOkActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnTest">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.bnTest.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnTestActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnCreateDb">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.bnCreateDb.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnCreateDbActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbTestIcon">
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbCreateIcon">
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="pnSetupGuidance">
|
||||
<Container class="javax.swing.JPanel" name="pnSQLiteSettings">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Setup Guidance">
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.pnSetupGuidance.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<Font PropertyName="font" name="Tahoma" size="12" style="0"/>
|
||||
</TitledBorder>
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
@ -434,55 +116,176 @@
|
||||
<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"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lbHostName" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbPort" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbUserName" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbDatabaseType" alignment="0" min="-2" pref="82" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lbDatabasePath" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbUserPassword" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="cbDatabaseType" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="lbSingleUserSqLite" pref="467" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="9" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="tfDatabasePath" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Component id="bnDatabasePathFileOpen" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="11" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="tbDbHostname" max="32767" attributes="0"/>
|
||||
<Component id="jpDbPassword" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="tbDbUsername" alignment="1" max="32767" attributes="0"/>
|
||||
<Component id="tbDbPort" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="cbDatabaseType" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbSingleUserSqLite" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="lbDatabaseType" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jScrollPane1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbDatabasePath" alignment="3" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<Component id="tfDatabasePath" alignment="3" min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<Component id="bnDatabasePathFileOpen" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="tbDbHostname" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbHostName" alignment="3" min="-2" pref="22" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="tbDbPort" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbPort" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="tbDbUsername" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbUserName" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbUserPassword" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
|
||||
<Component id="jpDbPassword" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
|
||||
<Component class="javax.swing.JLabel" name="lbDatabasePath">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbDatabasePath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JTextArea" name="taSetupGuidance">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="f0" green="f0" red="f0" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="columns" type="int" value="20"/>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Monospaced" size="12" style="0"/>
|
||||
</Property>
|
||||
<Property name="lineWrap" type="boolean" value="true"/>
|
||||
<Property name="rows" type="int" value="3"/>
|
||||
<Property name="tabSize" type="int" value="4"/>
|
||||
<Property name="wrapStyleWord" type="boolean" value="true"/>
|
||||
<Property name="autoscrolls" type="boolean" value="false"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
<Property name="requestFocusEnabled" type="boolean" value="false"/>
|
||||
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tfDatabasePath">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.tfDatabasePath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.tfDatabasePath.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnDatabasePathFileOpen">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.bnDatabasePathFileOpen.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnDatabasePathFileOpenActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbHostName">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbHostName.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbDbHostname">
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbPort">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbPort.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbDbPort">
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbUserName">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbUserName.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbDbUsername">
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbUserPassword">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbUserPassword.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JPasswordField" name="jpDbPassword">
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="cbDatabaseType">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new javax.swing.DefaultComboBoxModel<>(new EamDbPlatformEnum[]{EamDbPlatformEnum.POSTGRESQL, EamDbPlatformEnum.SQLITE})" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbDatabaseTypeActionPerformed"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<EamDbPlatformEnum>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbSingleUserSqLite">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbSingleUserSqLite.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbDatabaseType">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbDatabaseType.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,6 +25,10 @@
|
||||
<Component id="pnDatabaseContentButtons" max="32767" attributes="0"/>
|
||||
<Component id="tbOops" alignment="1" max="32767" attributes="0"/>
|
||||
<Component id="pnDatabaseConfiguration" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="cbUseCentralRepo" min="-2" pref="186" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@ -33,13 +37,14 @@
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="cbUseCentralRepo" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="pnDatabaseConfiguration" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="tbOops" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pnDatabaseContentButtons" min="-2" pref="50" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="18" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -240,5 +245,15 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="cbUseCentralRepo">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.cbUseCentralRepo.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbUseCentralRepoActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -29,6 +29,8 @@ import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbPlatformEnum;
|
||||
import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbPlatformEnum.DISABLED;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.PostgresEamDbSettings;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteEamDbSettings;
|
||||
|
||||
@ -53,7 +55,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
addIngestJobEventsListener();
|
||||
}
|
||||
|
||||
@Messages({"GlobalSettingsPanel.title=Central Repository Settings"})
|
||||
@Messages({"GlobalSettingsPanel.title=Central Repository Settings",
|
||||
"GlobalSettingsPanel.cbUseCentralRepo.text=Use a Central Repository"})
|
||||
private void customizeComponents() {
|
||||
setName(Bundle.GlobalSettingsPanel_title());
|
||||
}
|
||||
@ -85,6 +88,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
bnManageTags = new javax.swing.JButton();
|
||||
bnManageTypes = new javax.swing.JButton();
|
||||
tbOops = new javax.swing.JTextField();
|
||||
cbUseCentralRepo = new javax.swing.JCheckBox();
|
||||
|
||||
setName(""); // NOI18N
|
||||
|
||||
@ -198,6 +202,13 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N
|
||||
tbOops.setBorder(null);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cbUseCentralRepo, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.cbUseCentralRepo.text")); // NOI18N
|
||||
cbUseCentralRepo.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
cbUseCentralRepoActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
@ -207,50 +218,65 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(pnDatabaseContentButtons, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(tbOops, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(cbUseCentralRepo, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(cbUseCentralRepo)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(pnDatabaseContentButtons, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 18, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void bnImportDatabaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnImportDatabaseActionPerformed
|
||||
store();
|
||||
ImportHashDatabaseDialog dialog = new ImportHashDatabaseDialog();
|
||||
firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
||||
}//GEN-LAST:event_bnImportDatabaseActionPerformed
|
||||
|
||||
private void bnManageTagsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTagsActionPerformed
|
||||
store();
|
||||
ManageTagsDialog dialog = new ManageTagsDialog();
|
||||
firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
||||
}//GEN-LAST:event_bnManageTagsActionPerformed
|
||||
|
||||
private void bnManageTypesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTypesActionPerformed
|
||||
store();
|
||||
ManageCorrelationPropertiesDialog dialog = new ManageCorrelationPropertiesDialog();
|
||||
firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
||||
}//GEN-LAST:event_bnManageTypesActionPerformed
|
||||
|
||||
private void bnDbConfigureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDbConfigureActionPerformed
|
||||
store();
|
||||
EamDbSettingsDialog dialog = new EamDbSettingsDialog();
|
||||
load(); // reload db settings content and update buttons
|
||||
}//GEN-LAST:event_bnDbConfigureActionPerformed
|
||||
|
||||
private void cbUseCentralRepoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbUseCentralRepoActionPerformed
|
||||
//if saved setting is disabled checkbox should be disabled already
|
||||
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected());
|
||||
enableButtonSubComponents(cbUseCentralRepo.isSelected() && !EamDbPlatformEnum.getSelectedPlatform().equals(DISABLED));
|
||||
this.ingestStateUpdated();
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}//GEN-LAST:event_cbUseCentralRepoActionPerformed
|
||||
|
||||
@Override
|
||||
@Messages({"GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module."})
|
||||
public void load() {
|
||||
tbOops.setText("");
|
||||
|
||||
enableAllSubComponents(false);
|
||||
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
|
||||
|
||||
cbUseCentralRepo.setSelected(EamDbUtil.useCentralRepo()); // NON-NLS
|
||||
switch (selectedPlatform) {
|
||||
case POSTGRESQL:
|
||||
PostgresEamDbSettings dbSettingsPg = new PostgresEamDbSettings();
|
||||
@ -270,16 +296,16 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
lbDbPlatformValue.setText(EamDbPlatformEnum.DISABLED.toString());
|
||||
lbDbNameValue.setText("");
|
||||
lbDbLocationValue.setText("");
|
||||
enableDatabaseConfigureButton(true);
|
||||
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected());
|
||||
tbOops.setText(Bundle.GlobalSettingsPanel_validationerrMsg_mustConfigure());
|
||||
break;
|
||||
}
|
||||
|
||||
this.ingestStateUpdated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store() { // Click OK or Apply on Options Panel
|
||||
EamDbUtil.setUseCentralRepo(cbUseCentralRepo.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -293,6 +319,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
|
||||
@Override
|
||||
public void saveSettings() { // Click OK on Global Settings Panel
|
||||
store();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -334,7 +361,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
|
||||
if (IngestManager.getInstance().isIngestRunning()) {
|
||||
tbOops.setText(Bundle.GlobalSettingsPanel_validationErrMsg_ingestRunning());
|
||||
enableAllSubComponents(false);
|
||||
cbUseCentralRepo.setEnabled(false);
|
||||
} else if (!cbUseCentralRepo.isEnabled()) {
|
||||
cbUseCentralRepo.setEnabled(true);
|
||||
load();
|
||||
}
|
||||
}
|
||||
|
||||
@ -347,8 +377,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
* @return True
|
||||
*/
|
||||
private boolean enableAllSubComponents(Boolean enable) {
|
||||
enableDatabaseConfigureButton(enable);
|
||||
enableButtonSubComponents(enable);
|
||||
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && enable);
|
||||
enableButtonSubComponents(cbUseCentralRepo.isSelected() && enable);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -359,9 +389,18 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
*
|
||||
* @return True
|
||||
*/
|
||||
private boolean enableDatabaseConfigureButton(Boolean enable) {
|
||||
bnDbConfigure.setEnabled(enable);
|
||||
return true;
|
||||
private void enableDatabaseConfigureButton(Boolean enable) {
|
||||
boolean ingestRunning = IngestManager.getInstance().isIngestRunning();
|
||||
pnDatabaseConfiguration.setEnabled(enable && !ingestRunning);
|
||||
pnDatabaseContentButtons.setEnabled(enable && !ingestRunning);
|
||||
bnDbConfigure.setEnabled(enable && !ingestRunning);
|
||||
lbDbLocationLabel.setEnabled(enable && !ingestRunning);
|
||||
lbDbLocationValue.setEnabled(enable && !ingestRunning);
|
||||
lbDbNameLabel.setEnabled(enable && !ingestRunning);
|
||||
lbDbNameValue.setEnabled(enable && !ingestRunning);
|
||||
lbDbPlatformTypeLabel.setEnabled(enable && !ingestRunning);
|
||||
lbDbPlatformValue.setEnabled(enable && !ingestRunning);
|
||||
tbOops.setEnabled(enable && !ingestRunning);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -373,9 +412,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
* @return True
|
||||
*/
|
||||
private boolean enableButtonSubComponents(Boolean enable) {
|
||||
bnManageTypes.setEnabled(enable);
|
||||
bnImportDatabase.setEnabled(enable);
|
||||
bnManageTags.setEnabled(enable);
|
||||
boolean ingestRunning = IngestManager.getInstance().isIngestRunning();
|
||||
bnManageTypes.setEnabled(enable && !ingestRunning);
|
||||
bnImportDatabase.setEnabled(enable && !ingestRunning);
|
||||
bnManageTags.setEnabled(enable && !ingestRunning);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -384,6 +424,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
private javax.swing.JButton bnImportDatabase;
|
||||
private javax.swing.JButton bnManageTags;
|
||||
private javax.swing.JButton bnManageTypes;
|
||||
private javax.swing.JCheckBox cbUseCentralRepo;
|
||||
private javax.swing.JLabel lbDbLocationLabel;
|
||||
private javax.swing.JLabel lbDbLocationValue;
|
||||
private javax.swing.JLabel lbDbNameLabel;
|
||||
|
@ -72,6 +72,7 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
|
||||
|
||||
private final JFileChooser fileChooser = new JFileChooser();
|
||||
private final static String LAST_FILE_PATH_KEY = "CentralRepositoryImport_Path"; // NON-NLS
|
||||
private final int HASH_IMPORT_THRESHOLD = 10000;
|
||||
private EamOrganization selectedOrg = null;
|
||||
private List<EamOrganization> orgs = null;
|
||||
private final Collection<JTextField> textBoxes;
|
||||
@ -533,7 +534,8 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
|
||||
String errorMessage = Bundle.ImportHashDatabaseDialog_errorMessage_failedToOpenHashDbMsg(selectedFilePath);
|
||||
// Future, make UI handle more than the "FILES" type.
|
||||
try {
|
||||
EamArtifact.Type contentType = EamArtifact.getDefaultCorrelationTypes().get(0); // get "FILES" type
|
||||
EamDb dbManager = EamDb.getInstance();
|
||||
EamArtifact.Type contentType = dbManager.getCorrelationTypeById(EamArtifact.FILES_TYPE_ID); // get "FILES" type
|
||||
// run in the background and close dialog
|
||||
SwingUtilities.invokeLater(new ImportHashDatabaseWorker(selectedFilePath, knownStatus, globalSetID, contentType)::execute);
|
||||
dispose();
|
||||
@ -629,6 +631,7 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
|
||||
}
|
||||
|
||||
int numLines = 0;
|
||||
LOGGER.log(Level.INFO, "Importing hash database {0}", file.getName());
|
||||
while ((line = reader.readLine()) != null) {
|
||||
progress.progress(++numLines);
|
||||
|
||||
@ -646,9 +649,16 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
|
||||
"");
|
||||
|
||||
globalInstances.add(eamGlobalFileInstance);
|
||||
|
||||
if(numLines % HASH_IMPORT_THRESHOLD == 0){
|
||||
dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType);
|
||||
globalInstances.clear();
|
||||
}
|
||||
}
|
||||
|
||||
dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType);
|
||||
LOGGER.log(Level.INFO, "Finished importing hash database. Total entries: {0}", numLines);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import static java.util.Objects.nonNull;
|
||||
@ -153,7 +154,7 @@ public class ImageUtils {
|
||||
SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals); //NON-NLS
|
||||
|
||||
//Clear the file map when the case changes, so we don't accidentaly get images from the old case.
|
||||
Case.addEventSubscriber(Case.Events.CURRENT_CASE.toString(), evt -> cacheFileMap.clear());
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), evt -> cacheFileMap.clear());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,8 +21,10 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -53,6 +55,9 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
@NbBundle.Messages("AbstractAbstractFileNode.addFileProperty.desc=no description")
|
||||
private static final String NO_DESCR = AbstractAbstractFileNode_addFileProperty_desc();
|
||||
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE,
|
||||
Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED);
|
||||
|
||||
/**
|
||||
* @param abstractFile file to wrap
|
||||
*/
|
||||
@ -67,13 +72,14 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
}
|
||||
}
|
||||
// Listen for case events so that we can detect when case is closed
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
// Listen for case events so that we can detect when the case is closed
|
||||
// or when tags are added.
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||
@ -95,7 +101,11 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
// If so, refresh our children.
|
||||
try {
|
||||
Children parentsChildren = getParentNode().getChildren();
|
||||
if (parentsChildren != null) {
|
||||
// We only want to refresh our parents children if we are in the
|
||||
// data sources branch of the tree. The parent nodes in other
|
||||
// branches of the tree (e.g. File Types and Deleted Files) do
|
||||
// not need to be refreshed.
|
||||
if (parentsChildren instanceof ContentChildren) {
|
||||
((ContentChildren) parentsChildren).refreshChildren();
|
||||
parentsChildren.getNodesCount();
|
||||
}
|
||||
|
@ -18,14 +18,20 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
|
||||
/**
|
||||
@ -84,6 +90,47 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying content object has children Useful for lazy
|
||||
* loading.
|
||||
*
|
||||
* @return true if has children
|
||||
*/
|
||||
public boolean hasVisibleContentChildren() {
|
||||
return contentHasVisibleContentChildren(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given content object has children. Useful for lazy
|
||||
* loading.
|
||||
*
|
||||
* @param c The content object to look for children on
|
||||
* @return true if has children
|
||||
*/
|
||||
public static boolean contentHasVisibleContentChildren(Content c){
|
||||
if (c != null) {
|
||||
String query = "SELECT COUNT(obj_id) AS count FROM "
|
||||
+ " ( SELECT obj_id FROM tsk_objects WHERE par_obj_id = " + c.getId() + " AND type = "
|
||||
+ TskData.ObjectType.ARTIFACT.getObjectType()
|
||||
+ " INTERSECT SELECT artifact_obj_id FROM blackboard_artifacts WHERE obj_id = " + c.getId()
|
||||
+ " AND (artifact_type_id = " + ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()
|
||||
+ " OR artifact_type_id = " + ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + ") "
|
||||
+ " UNION SELECT obj_id FROM tsk_objects WHERE par_obj_id = " + c.getId()
|
||||
+ " AND type = " + TskData.ObjectType.ABSTRACTFILE.getObjectType() + ")"; //NON-NLS;
|
||||
|
||||
|
||||
try (SleuthkitCase.CaseDbQuery dbQuery = Case.getCurrentCase().getSleuthkitCase().executeQuery(query)) {
|
||||
ResultSet resultSet = dbQuery.getResultSet();
|
||||
if(resultSet.next()){
|
||||
return (0 < resultSet.getInt("count"));
|
||||
}
|
||||
} catch (TskCoreException | SQLException ex) {
|
||||
logger.log(Level.SEVERE, "Error checking if the node has children, for content: " + c, ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying content object has children Useful for lazy
|
||||
* loading.
|
||||
@ -103,7 +150,7 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
||||
|
||||
return hasChildren;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return ids of children of the underlying content. The ids can be treated
|
||||
* as keys - useful for lazy loading.
|
||||
|
@ -25,31 +25,29 @@ import java.beans.PropertyChangeListener;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.WeakListeners;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import static org.sleuthkit.autopsy.datamodel.DataModelActionsFactory.VIEW_IN_NEW_WINDOW;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
@ -68,6 +66,11 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactNode.class.getName());
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
|
||||
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED,
|
||||
Case.Events.CONTENT_TAG_ADDED,
|
||||
Case.Events.CONTENT_TAG_DELETED,
|
||||
Case.Events.CURRENT_CASE);
|
||||
|
||||
private static Cache<Long, Content> contentCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.MINUTES).
|
||||
@ -76,7 +79,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
private final BlackboardArtifact artifact;
|
||||
private Content associated = null;
|
||||
private List<NodeProperty<? extends Object>> customProperties;
|
||||
|
||||
|
||||
/*
|
||||
* Artifact types which should have the full unique path of the associated
|
||||
* content as a property.
|
||||
@ -128,8 +131,9 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct blackboard artifact node from an artifact and using provided
|
||||
* icon
|
||||
* Construct blackboard artifact node from an artifact, overriding the
|
||||
* standard icon with the one at the path provided.
|
||||
*
|
||||
*
|
||||
* @param artifact artifact to encapsulate
|
||||
* @param iconPath icon to use for the artifact
|
||||
@ -138,19 +142,19 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
super(artifact, createLookup(artifact));
|
||||
|
||||
this.artifact = artifact;
|
||||
|
||||
|
||||
// Look for associated Content i.e. the source file for the artifact
|
||||
for (Content content : this.getLookup().lookupAll(Content.class)) {
|
||||
if ( (content != null) && (!(content instanceof BlackboardArtifact)) ){
|
||||
this.associated = content;
|
||||
for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
|
||||
if ((lookupContent != null) && (!(lookupContent instanceof BlackboardArtifact))) {
|
||||
this.associated = lookupContent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.setName(Long.toString(artifact.getArtifactID()));
|
||||
this.setDisplayName();
|
||||
this.setIconBaseWithExtension(iconPath);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, WeakListeners.propertyChange(pcl, null));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,18 +164,17 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
* @param artifact artifact to encapsulate
|
||||
*/
|
||||
public BlackboardArtifactNode(BlackboardArtifact artifact) {
|
||||
|
||||
this(artifact, ExtractedContent.getIconFilePath(artifact.getArtifactTypeID()));
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
public BlackboardArtifact getArtifact() {
|
||||
return this.artifact;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages({
|
||||
"BlackboardArtifactNode.getAction.errorTitle=Error getting actions",
|
||||
@ -221,7 +224,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
*/
|
||||
private void setDisplayName() {
|
||||
String displayName = ""; //NON-NLS
|
||||
|
||||
|
||||
// If this is a node for a keyword hit on an artifact, we set the
|
||||
// display name to be the artifact type name followed by " Artifact"
|
||||
// e.g. "Messages Artifact".
|
||||
@ -245,30 +248,29 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
// Do nothing since the display name will be set to the file name.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (displayName.isEmpty() && artifact != null) {
|
||||
displayName = artifact.getName();
|
||||
}
|
||||
|
||||
|
||||
this.setDisplayName(displayName);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the associated source file/content
|
||||
*
|
||||
* Return the name of the associated source file/content
|
||||
*
|
||||
* @return source file/content name
|
||||
*/
|
||||
public String getSrcName() {
|
||||
|
||||
|
||||
String srcName = "";
|
||||
if (associated != null) {
|
||||
srcName = associated.getName();
|
||||
srcName = associated.getName();
|
||||
}
|
||||
return srcName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@NbBundle.Messages({
|
||||
"BlackboardArtifactNode.createSheet.artifactType.displayName=Artifact Type",
|
||||
"BlackboardArtifactNode.createSheet.artifactType.name=Artifact Type",
|
||||
@ -476,11 +478,9 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()) {
|
||||
}
|
||||
else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
|
||||
addEmailMsgProperty (map, attribute);
|
||||
}
|
||||
else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
|
||||
} else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
|
||||
addEmailMsgProperty(map, attribute);
|
||||
} else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
|
||||
map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
|
||||
} else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID()
|
||||
&& attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
|
||||
@ -496,8 +496,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
value = value.substring(0, 512);
|
||||
}
|
||||
map.put(attribute.getAttributeType().getDisplayName(), value);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
|
||||
}
|
||||
}
|
||||
@ -506,14 +505,14 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Fill map with EmailMsg properties, not all attributes are filled
|
||||
*
|
||||
* @param map map with preserved ordering, where property names/values
|
||||
* are put
|
||||
* @param attribute attribute to check/fill as property
|
||||
*/
|
||||
private void addEmailMsgProperty(Map<String, Object> map, BlackboardAttribute attribute ) {
|
||||
private void addEmailMsgProperty(Map<String, Object> map, BlackboardAttribute attribute) {
|
||||
|
||||
final int attributeTypeID = attribute.getAttributeType().getTypeID();
|
||||
|
||||
@ -523,23 +522,19 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID()
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()
|
||||
) {
|
||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()) {
|
||||
|
||||
// do nothing
|
||||
}
|
||||
else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) {
|
||||
} else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) {
|
||||
|
||||
String value = attribute.getDisplayString();
|
||||
if (value.length() > 160) {
|
||||
value = value.substring(0, 160) + "...";
|
||||
}
|
||||
map.put(attribute.getAttributeType().getDisplayName(), value);
|
||||
}
|
||||
else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
|
||||
} else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
|
||||
map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
|
||||
}
|
||||
|
||||
@ -586,6 +581,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
return v.visit(this);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.Sheet;
|
||||
@ -88,13 +89,13 @@ public class DataSourcesNode extends DisplayableItemNode {
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
|
||||
reloadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
|
||||
currentKeys.clear();
|
||||
setKeys(Collections.<Content>emptySet());
|
||||
}
|
||||
|
@ -22,9 +22,11 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
@ -173,68 +175,69 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
* Listens for case and ingest invest. Updates observers when events are
|
||||
* fired. Other nodes are listening to this for changes.
|
||||
*/
|
||||
private final class DeletedContentsChildrenObservable extends Observable {
|
||||
private static final class DeletedContentsChildrenObservable extends Observable {
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(
|
||||
Case.Events.DATA_SOURCE_ADDED,
|
||||
Case.Events.CURRENT_CASE
|
||||
);
|
||||
|
||||
DeletedContentsChildrenObservable() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
|
||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
|
||||
/**
|
||||
* + // @@@ COULD CHECK If the new file is deleted
|
||||
* before notifying... Checking for a current case is a
|
||||
* stop gap measure + update(); until a different way of
|
||||
* handling the closing of cases is worked out.
|
||||
* Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
// new file was added
|
||||
// @@@ COULD CHECK If the new file is deleted before notifying...
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* + // @@@ COULD CHECK If the new file is deleted
|
||||
* before notifying... Checking for a current case is a
|
||||
* stop gap measure + update(); until a different way of
|
||||
* handling the closing of cases is worked out.
|
||||
* Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
// new file was added
|
||||
// @@@ COULD CHECK If the new file is deleted before notifying...
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure
|
||||
* until a different way of handling the closing of
|
||||
* cases is worked out. Currently, remote events may be
|
||||
* received for a case that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeListeners();
|
||||
}
|
||||
maxFilesDialogShown = false;
|
||||
}
|
||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure
|
||||
* until a different way of handling the closing of
|
||||
* cases is worked out. Currently, remote events may be
|
||||
* received for a case that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeListeners();
|
||||
}
|
||||
maxFilesDialogShown = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@ -285,7 +286,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
protected void addNotify() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
emailResults.update();
|
||||
emailResults.addObserver(this);
|
||||
}
|
||||
@ -294,7 +295,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
protected void removeNotify() {
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
emailResults.deleteObserver(this);
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
@ -251,14 +252,14 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
protected void addNotify() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
typeNodeList.clear();
|
||||
}
|
||||
|
||||
@ -309,7 +310,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
||||
*/
|
||||
public class TypeNode extends DisplayableItemNode {
|
||||
|
||||
private BlackboardArtifact.Type type;
|
||||
private final BlackboardArtifact.Type type;
|
||||
private long childCount = 0;
|
||||
|
||||
TypeNode(BlackboardArtifact.Type type) {
|
||||
|
@ -22,9 +22,11 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
@ -169,65 +171,64 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
* Listens for case and ingest invest. Updates observers when events are
|
||||
* fired. Size-based nodes are listening to this for changes.
|
||||
*/
|
||||
private final class FileSizeRootChildrenObservable extends Observable {
|
||||
private static final class FileSizeRootChildrenObservable extends Observable {
|
||||
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.CURRENT_CASE);
|
||||
|
||||
FileSizeRootChildrenObservable() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
* out. Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
*/
|
||||
try {
|
||||
// new file was added
|
||||
// @@@ could check the size here and only fire off updates if we know the file meets the min size criteria
|
||||
Case.getCurrentCase();
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure
|
||||
* until a different way of handling the closing of
|
||||
* cases is worked out. Currently, remote events may be
|
||||
* received for a case that is already closed.
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
try {
|
||||
// new file was added
|
||||
// @@@ could check the size here and only fire off updates if we know the file meets the min size criteria
|
||||
Case.getCurrentCase();
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
}
|
||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
* out. Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure
|
||||
* until a different way of handling the closing of
|
||||
* cases is worked out. Currently, remote events may be
|
||||
* received for a case that is already closed.
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeListeners();
|
||||
}
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeListeners();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -21,10 +21,11 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.function.Function;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
@ -39,8 +40,6 @@ import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
@ -75,9 +74,11 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
private class FileTypesByExtObservable extends Observable {
|
||||
|
||||
private final PropertyChangeListener pcl;
|
||||
private final Set<Case.Events> CASE_EVENTS_OF_INTEREST;
|
||||
|
||||
private FileTypesByExtObservable() {
|
||||
super();
|
||||
this.CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.CURRENT_CASE);
|
||||
this.pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
|
||||
@ -109,15 +110,14 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
||||
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
private void update() {
|
||||
|
@ -24,11 +24,13 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -44,7 +46,6 @@ import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTr
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
@ -79,6 +80,8 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
*/
|
||||
private final PropertyChangeListener pcl;
|
||||
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.CURRENT_CASE);
|
||||
|
||||
/**
|
||||
* Create the base expression used as the where clause in the queries for
|
||||
* files by mime type. Filters out certain kinds of files and directories,
|
||||
@ -102,7 +105,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
private void removeListeners() {
|
||||
deleteObservers();
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,7 +178,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
||||
}
|
||||
};
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
populateHashMap();
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -252,7 +253,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
protected void addNotify() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
hashsetResults.update();
|
||||
hashsetResults.addObserver(this);
|
||||
}
|
||||
@ -261,7 +262,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
protected void removeNotify() {
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
hashsetResults.deleteObserver(this);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
@ -79,12 +80,12 @@ public class ImageNode extends AbstractContentNode<Image> {
|
||||
// Listen for ingest events so that we can detect new added files (e.g. carved)
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
// Listen for case events so that we can detect when case is closed
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,6 +24,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -188,57 +189,54 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
* nice methods for its startup and shutdown, so it seemed like a
|
||||
* cleaner place to register the property change listener.
|
||||
*/
|
||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
* out. Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
* out. Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
* Even with the check above, it is still possible that
|
||||
* the case will be closed in a different thread before
|
||||
* this code executes. If that happens, it is possible
|
||||
* for the event to have a null oldValue.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
/**
|
||||
* Even with the check above, it is still possible that
|
||||
* the case will be closed in a different thread before
|
||||
* this code executes. If that happens, it is possible
|
||||
* for the event to have a null oldValue.
|
||||
*/
|
||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||
if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()
|
||||
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())) {
|
||||
interestingResults.update();
|
||||
}
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
* out. Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||
if (null != eventData && (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()
|
||||
|| eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())) {
|
||||
interestingResults.update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeNotify();
|
||||
skCase = null;
|
||||
}
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
* out. Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCase();
|
||||
interestingResults.update();
|
||||
} catch (IllegalStateException notUsed) {
|
||||
/**
|
||||
* Case is closed, do nothing.
|
||||
*/
|
||||
}
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
removeNotify();
|
||||
skCase = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -247,7 +245,7 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
protected void addNotify() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
interestingResults.update();
|
||||
interestingResults.addObserver(this);
|
||||
}
|
||||
@ -256,7 +254,7 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
protected void removeNotify() {
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
interestingResults.deleteObserver(this);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@ -455,7 +456,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
protected void addNotify() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
keywordResults.update();
|
||||
super.addNotify();
|
||||
}
|
||||
@ -464,7 +465,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
protected void removeNotify() {
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
super.removeNotify();
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,9 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
@ -103,8 +105,10 @@ public final class Reports implements AutopsyVisitableItem {
|
||||
*/
|
||||
private static final class ReportNodeFactory extends ChildFactory<Report> {
|
||||
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.REPORT_ADDED, Case.Events.REPORT_DELETED);
|
||||
|
||||
ReportNodeFactory() {
|
||||
Case.addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, (PropertyChangeEvent evt) -> {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(Case.Events.REPORT_ADDED.toString()) || eventType.equals(Case.Events.REPORT_DELETED.toString())) {
|
||||
/**
|
||||
|
@ -21,9 +21,11 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
@ -118,6 +120,12 @@ public class Tags implements AutopsyVisitableItem {
|
||||
|
||||
private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer {
|
||||
|
||||
private final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
|
||||
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED,
|
||||
Case.Events.CONTENT_TAG_ADDED,
|
||||
Case.Events.CONTENT_TAG_DELETED,
|
||||
Case.Events.CURRENT_CASE);
|
||||
|
||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
@ -171,7 +179,7 @@ public class Tags implements AutopsyVisitableItem {
|
||||
protected void addNotify() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
tagResults.update();
|
||||
tagResults.addObserver(this);
|
||||
}
|
||||
@ -180,7 +188,7 @@ public class Tags implements AutopsyVisitableItem {
|
||||
protected void removeNotify() {
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||
tagResults.deleteObserver(this);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Children;
|
||||
@ -72,12 +73,12 @@ public class VolumeNode extends AbstractContentNode<Volume> {
|
||||
// Listen for ingest events so that we can detect new added files (e.g. carved)
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
// Listen for case events so that we can detect when case is closed
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
}
|
||||
|
||||
private void removeListeners() {
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -32,6 +32,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -311,7 +312,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
protected void removeNotify() {
|
||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
super.removeNotify();
|
||||
}
|
||||
|
||||
@ -319,7 +320,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
||||
protected void addNotify() {
|
||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||
Case.addPropertyChangeListener(pcl);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||
super.addNotify();
|
||||
refreshKeys();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
@ -129,8 +130,10 @@ final class AddRawImageTask implements Runnable {
|
||||
|
||||
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());
|
||||
String errorMessage = Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePath + Bundle.AddRawImageTask_for_device()
|
||||
+ deviceId + Bundle.AddRawImageTask_image_notExisting();
|
||||
errorMessages.add(errorMessage);
|
||||
logger.log(Level.SEVERE, errorMessage);
|
||||
criticalErrorOccurred = true;
|
||||
return;
|
||||
}
|
||||
@ -173,7 +176,9 @@ final class AddRawImageTask implements Runnable {
|
||||
caseDatabase.addLayoutFiles(dataSource, fileRanges);
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
errorMessages.add(Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePaths + Bundle.AddRawImageTask_for_device() + deviceId + ":" + ex.getLocalizedMessage());
|
||||
String errorMessage = Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePaths + Bundle.AddRawImageTask_for_device() + deviceId + ":" + ex.getLocalizedMessage();
|
||||
errorMessages.add(errorMessage);
|
||||
logger.log(Level.SEVERE, errorMessage, ex);
|
||||
criticalErrorOccurred = true;
|
||||
} finally {
|
||||
caseDatabase.releaseExclusiveLock();
|
||||
|
@ -26,6 +26,7 @@ import org.sleuthkit.autopsy.datamodel.DirectoryNode;
|
||||
import org.openide.nodes.FilterNode;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.AbstractContentNode;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||
@ -42,7 +43,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
import org.sleuthkit.datamodel.Volume;
|
||||
@ -120,7 +120,7 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
||||
&& !((Directory) c).getName().equals(".."))) {
|
||||
ret = false;
|
||||
break;
|
||||
} else if (c.hasChildren()) {
|
||||
} else if(AbstractContentNode.contentHasVisibleContentChildren(c)){
|
||||
//fie has children, such as derived files
|
||||
ret = false;
|
||||
break;
|
||||
@ -204,12 +204,8 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
||||
if ((childContent instanceof AbstractFile) && ((AbstractFile) childContent).isDir()) {
|
||||
return false;
|
||||
} else {
|
||||
try {
|
||||
if (childContent.hasChildren()) {
|
||||
return false;
|
||||
}
|
||||
} catch (TskCoreException e) {
|
||||
logger.log(Level.SEVERE, "Error checking if file node is leaf.", e); //NON-NLS
|
||||
if(AbstractContentNode.contentHasVisibleContentChildren(childContent)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -244,7 +240,6 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
||||
@Override
|
||||
public Boolean visit(VirtualDirectoryNode vdn) {
|
||||
return visitDeep(vdn);
|
||||
//return ! vdn.hasContentChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -286,7 +281,7 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
||||
|
||||
@Override
|
||||
public Boolean visit(FileNode fn) {
|
||||
return fn.hasContentChildren();
|
||||
return fn.hasVisibleContentChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,7 +25,6 @@ import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.FilterNode;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.openide.util.lookup.ProxyLookup;
|
||||
@ -36,6 +35,7 @@ import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
@ -120,7 +120,7 @@ class DirectoryTreeFilterNode extends FilterNode {
|
||||
private int getVisibleChildCount(AbstractFile file) throws TskCoreException {
|
||||
List<Content> childList = file.getChildren();
|
||||
|
||||
int numVisibleChildren = file.getChildrenCount();
|
||||
int numVisibleChildren = childList.size();
|
||||
boolean purgeKnownFiles = UserPreferences.hideKnownFilesInDataSourcesTree();
|
||||
boolean purgeSlackFiles = UserPreferences.hideSlackFilesInDataSourcesTree();
|
||||
|
||||
@ -134,6 +134,14 @@ class DirectoryTreeFilterNode extends FilterNode {
|
||||
|| (purgeSlackFiles && childFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) {
|
||||
numVisibleChildren--;
|
||||
}
|
||||
} else if(child instanceof BlackboardArtifact){
|
||||
BlackboardArtifact bba = (BlackboardArtifact) child;
|
||||
|
||||
// Only message type artifacts are displayed in the tree
|
||||
if((bba.getArtifactTypeID() != ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())
|
||||
&& (bba.getArtifactTypeID() != ARTIFACT_TYPE.TSK_MESSAGE.getTypeID())){
|
||||
numVisibleChildren--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import java.beans.PropertyVetoException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@ -151,7 +152,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
}
|
||||
}
|
||||
});
|
||||
Case.addEventSubscriber(new HashSet<>(Arrays.asList(Case.Events.CURRENT_CASE.toString(), Case.Events.DATA_SOURCE_ADDED.toString())), this);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE, Case.Events.DATA_SOURCE_ADDED), this);
|
||||
this.em.addPropertyChangeListener(this);
|
||||
IngestManager.getInstance().addIngestJobEventListener(this);
|
||||
IngestManager.getInstance().addIngestModuleEventListener(this);
|
||||
|
@ -56,3 +56,5 @@ SizeSearchPanel.sizeCompareComboBox.lessThan=less than
|
||||
MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected
|
||||
FileSearchPanel.searchButton.text=Search
|
||||
MimeTypePanel.mimeTypeCheckBox.text=MIME Type:
|
||||
HashSearchPanel.md5CheckBox.text=MD5:
|
||||
HashSearchPanel.emptyHashMsg.text=Must enter something for hash search.
|
@ -28,6 +28,7 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -53,6 +54,9 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
|
||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy");
|
||||
private static final String SEPARATOR = "SEPARATOR"; //NON-NLS
|
||||
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE,
|
||||
Case.Events.DATA_SOURCE_ADDED, Case.Events.DATA_SOURCE_DELETED);
|
||||
|
||||
/**
|
||||
* New DateSearchFilter with the default panel
|
||||
*/
|
||||
@ -62,7 +66,7 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
|
||||
|
||||
private DateSearchFilter(DateSearchPanel panel) {
|
||||
super(panel);
|
||||
Case.addPropertyChangeListener(this.new CasePropertyChangeListener());
|
||||
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, this.new CasePropertyChangeListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.filesearch;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.EnumSet;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
@ -35,14 +35,10 @@ final class FileSearchAction extends CallableSystemAction implements FileSearchP
|
||||
FileSearchAction() {
|
||||
super();
|
||||
setEnabled(Case.isCaseOpen());
|
||||
Case.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
setEnabled(evt.getNewValue() != null);
|
||||
}
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
setEnabled(evt.getNewValue() != null);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,8 @@ class FileSearchPanel extends javax.swing.JPanel {
|
||||
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.metadata"), metadataFilters));
|
||||
|
||||
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.knownStatus"), new KnownStatusSearchFilter()));
|
||||
|
||||
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "HashSearchPanel.md5CheckBox.text"), new HashSearchFilter()));
|
||||
|
||||
for (FilterArea fa : this.filterAreas) {
|
||||
fa.setMaximumSize(new Dimension(Integer.MAX_VALUE, fa.getMinimumSize().height));
|
||||
|
66
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java
Executable file
66
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java
Executable file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.filesearch;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class HashSearchFilter extends AbstractFileSearchFilter<HashSearchPanel> {
|
||||
|
||||
private static final String EMPTY_HASH_MESSAGE = NbBundle
|
||||
.getMessage(HashSearchFilter.class, "HashSearchPanel.emptyHashMsg.text");
|
||||
|
||||
public HashSearchFilter() {
|
||||
this(new HashSearchPanel());
|
||||
}
|
||||
|
||||
public HashSearchFilter(HashSearchPanel component) {
|
||||
super(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.getComponent().getHashCheckBox().isSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPredicate() throws FilterValidationException {
|
||||
String md5Hash = this.getComponent().getSearchTextField().getText();
|
||||
|
||||
if (md5Hash.isEmpty()) {
|
||||
throw new FilterValidationException(EMPTY_HASH_MESSAGE);
|
||||
}
|
||||
|
||||
return "md5 = '" + md5Hash.toLowerCase() + "'"; //NON-NLS
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionListener(ActionListener l) {
|
||||
getComponent().addActionListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return !this.getComponent().getSearchTextField().getText().isEmpty();
|
||||
}
|
||||
}
|
101
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchPanel.form
Executable file
101
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchPanel.form
Executable file
@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<NonVisualComponents>
|
||||
<Container class="javax.swing.JPopupMenu" name="rightClickMenu">
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
|
||||
<Property name="useNullLayout" type="boolean" value="true"/>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<MenuItem class="javax.swing.JMenuItem" name="cutMenuItem">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.cutMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</MenuItem>
|
||||
<MenuItem class="javax.swing.JMenuItem" name="copyMenuItem">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.copyMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</MenuItem>
|
||||
<MenuItem class="javax.swing.JMenuItem" name="pasteMenuItem">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.pasteMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</MenuItem>
|
||||
<MenuItem class="javax.swing.JMenuItem" name="selectAllMenuItem">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.selectAllMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</MenuItem>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</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="false"/>
|
||||
<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">
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="hashCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="searchTextField" min="-2" pref="247" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="hashCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="searchTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JCheckBox" name="hashCheckBox">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||
<FontInfo relative="true">
|
||||
<Font bold="false" component="hashCheckBox" property="font" relativeSize="false" size="11"/>
|
||||
</FontInfo>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="HashSearchPanel.md5CheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="hashCheckBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="searchTextField">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||
<FontInfo relative="true">
|
||||
<Font bold="false" component="searchTextField" property="font" relativeSize="false" size="11"/>
|
||||
</FontInfo>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
175
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchPanel.java
Executable file
175
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchPanel.java
Executable file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.filesearch;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class HashSearchPanel extends javax.swing.JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates new form HashSearchPanel
|
||||
*/
|
||||
HashSearchPanel() {
|
||||
initComponents();
|
||||
customizeComponents();
|
||||
setComponentsEnabled();
|
||||
}
|
||||
|
||||
private void customizeComponents() {
|
||||
|
||||
searchTextField.setComponentPopupMenu(rightClickMenu);
|
||||
ActionListener actList = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem jmi = (JMenuItem) e.getSource();
|
||||
if (jmi.equals(cutMenuItem)) {
|
||||
searchTextField.cut();
|
||||
} else if (jmi.equals(copyMenuItem)) {
|
||||
searchTextField.copy();
|
||||
} else if (jmi.equals(pasteMenuItem)) {
|
||||
searchTextField.paste();
|
||||
} else if (jmi.equals(selectAllMenuItem)) {
|
||||
searchTextField.selectAll();
|
||||
}
|
||||
}
|
||||
};
|
||||
cutMenuItem.addActionListener(actList);
|
||||
copyMenuItem.addActionListener(actList);
|
||||
pasteMenuItem.addActionListener(actList);
|
||||
selectAllMenuItem.addActionListener(actList);
|
||||
this.searchTextField.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
JCheckBox getHashCheckBox() {
|
||||
return hashCheckBox;
|
||||
}
|
||||
|
||||
JTextField getSearchTextField() {
|
||||
return searchTextField;
|
||||
}
|
||||
|
||||
void setComponentsEnabled() {
|
||||
boolean enabled = hashCheckBox.isSelected();
|
||||
this.searchTextField.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
rightClickMenu = new javax.swing.JPopupMenu();
|
||||
cutMenuItem = new javax.swing.JMenuItem();
|
||||
copyMenuItem = new javax.swing.JMenuItem();
|
||||
pasteMenuItem = new javax.swing.JMenuItem();
|
||||
selectAllMenuItem = new javax.swing.JMenuItem();
|
||||
hashCheckBox = new javax.swing.JCheckBox();
|
||||
searchTextField = new javax.swing.JTextField();
|
||||
|
||||
cutMenuItem.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "NameSearchPanel.cutMenuItem.text")); // NOI18N
|
||||
rightClickMenu.add(cutMenuItem);
|
||||
|
||||
copyMenuItem.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "NameSearchPanel.copyMenuItem.text")); // NOI18N
|
||||
rightClickMenu.add(copyMenuItem);
|
||||
|
||||
pasteMenuItem.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "NameSearchPanel.pasteMenuItem.text")); // NOI18N
|
||||
rightClickMenu.add(pasteMenuItem);
|
||||
|
||||
selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "NameSearchPanel.selectAllMenuItem.text")); // NOI18N
|
||||
rightClickMenu.add(selectAllMenuItem);
|
||||
|
||||
hashCheckBox.setFont(hashCheckBox.getFont().deriveFont(hashCheckBox.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
|
||||
hashCheckBox.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "HashSearchPanel.md5CheckBox.text")); // NOI18N
|
||||
hashCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
hashCheckBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
searchTextField.setFont(searchTextField.getFont().deriveFont(searchTextField.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(hashCheckBox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 247, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(hashCheckBox)
|
||||
.addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void hashCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashCheckBoxActionPerformed
|
||||
setComponentsEnabled();
|
||||
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||
}//GEN-LAST:event_hashCheckBoxActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JMenuItem copyMenuItem;
|
||||
private javax.swing.JMenuItem cutMenuItem;
|
||||
private javax.swing.JCheckBox hashCheckBox;
|
||||
private javax.swing.JMenuItem pasteMenuItem;
|
||||
private javax.swing.JPopupMenu rightClickMenu;
|
||||
private javax.swing.JTextField searchTextField;
|
||||
private javax.swing.JMenuItem selectAllMenuItem;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
void addActionListener(ActionListener l) {
|
||||
searchTextField.addActionListener(l);
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -229,7 +230,7 @@ public class IngestManager {
|
||||
* opened/closed) events.
|
||||
*/
|
||||
private void subscribeToCaseEvents() {
|
||||
Case.addEventSubscriber(Case.Events.CURRENT_CASE.toString(), (PropertyChangeEvent event) -> {
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent event) -> {
|
||||
if (event.getNewValue() != null) {
|
||||
handleCaseOpened();
|
||||
} else {
|
||||
|
@ -25,6 +25,7 @@ import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.EnumSet;
|
||||
import javax.swing.JButton;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.Mode;
|
||||
@ -128,7 +129,7 @@ class IngestMessagesToolbar extends javax.swing.JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
Case.addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
setEnabled(evt.getNewValue() != null && RuntimeProperties.runningWithGUI());
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import java.awt.event.ActionListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.SimpleFormatter;
|
||||
@ -121,7 +122,7 @@ public final class IngestMonitor {
|
||||
|
||||
MonitorTimerAction() {
|
||||
findRootDirectoryForCurrentCase();
|
||||
Case.addEventSubscriber(Case.Events.CURRENT_CASE.toString(), (PropertyChangeEvent evt) -> {
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||
if (evt instanceof AutopsyEvent) {
|
||||
AutopsyEvent event = (AutopsyEvent) evt;
|
||||
if (AutopsyEvent.SourceType.LOCAL == event.getSourceType() && event.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
|
@ -23,7 +23,7 @@ import java.awt.event.ActionListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.EnumSet;
|
||||
import org.openide.util.HelpCtx;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
@ -43,13 +43,9 @@ class HashDbPanelSearchAction extends CallableSystemAction {
|
||||
HashDbPanelSearchAction() {
|
||||
super();
|
||||
setEnabled(Case.isCaseOpen());
|
||||
Case.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
setEnabled(evt.getNewValue() != null);
|
||||
}
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
setEnabled(evt.getNewValue() != null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
@ -81,7 +82,7 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr
|
||||
|
||||
public ReportWizardAction() {
|
||||
setEnabled(false);
|
||||
Case.addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
Case newCase = (Case) evt.getNewValue();
|
||||
setEnabled(newCase != null && RuntimeProperties.runningWithGUI());
|
||||
|
@ -24,7 +24,7 @@
|
||||
Note there is no namespace collision with ver 3 -->
|
||||
<dependency conf="autopsy_core->*" org="commons-lang" name="commons-lang" rev="2.6"/>
|
||||
<dependency conf="autopsy_core->*" org="commons-logging" name="commons-logging" rev="1.1.2"/>
|
||||
<dependency conf="autopsy_core->*" org="commons-io" name="commons-io" rev="2.4"/>
|
||||
<dependency conf="autopsy_core->*" org="commons-io" name="commons-io" rev="2.5"/>
|
||||
<dependency conf="autopsy_core->*" org="log4j" name="log4j" rev="1.2.17"/>
|
||||
|
||||
<!-- <dependency conf="autopsy_core->*" org="org.jdom" name="jdom" rev="1.1.3"/> -->
|
||||
|
@ -10,6 +10,7 @@ file.reference.commons-codec-1.10.jar=release/modules/ext/commons-codec-1.10.jar
|
||||
file.reference.commons-collections4-4.1.jar=release/modules/ext/commons-collections4-4.1.jar
|
||||
file.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4.jar
|
||||
file.reference.commons-io-2.4.jar=release/modules/ext/commons-io-2.4.jar
|
||||
file.reference.commons-io-2.5.jar=release/modules/ext/commons-io-2.5.jar
|
||||
file.reference.commons-lang-2.6.jar=release/modules/ext/commons-lang-2.6.jar
|
||||
file.reference.commons-lang3-3.0-javadoc.jar=release/modules/ext/commons-lang3-3.0-javadoc.jar
|
||||
file.reference.commons-lang3-3.0-sources.jar=release/modules/ext/commons-lang3-3.0-sources.jar
|
||||
@ -74,6 +75,7 @@ file.reference.xmlbeans-2.6.0.jar=release/modules/ext/xmlbeans-2.6.0.jar
|
||||
javac.source=1.8
|
||||
javac.compilerargs=-Xlint -Xlint:-serial
|
||||
javadoc.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-javadoc.jar
|
||||
javadoc.reference.commons-io-2.5.jar=release/modules/ext/commons-io-2.5-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-19.0.jar=release/modules/ext/guava-19.0-javadoc.jar
|
||||
@ -82,6 +84,7 @@ javadoc.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-contro
|
||||
javadoc.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-javadoc.jar
|
||||
nbm.needs.restart=true
|
||||
source.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-sources.jar
|
||||
source.reference.commons-io-2.5.jar=release/modules/ext/commons-io-2.5-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-19.0.jar=release/modules/ext/guava-19.0-sources.jar
|
||||
|
@ -699,18 +699,10 @@
|
||||
<runtime-relative-path>ext/sigar-1.6.4.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sigar-1.6.4.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/xmlbeans-2.6.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/xmlbeans-2.6.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jna-3.4.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jna-3.4.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/poi-ooxml-schemas-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-ooxml-schemas-3.15.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/gson-1.4.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/gson-1.4.jar</binary-origin>
|
||||
@ -731,6 +723,10 @@
|
||||
<runtime-relative-path>ext/imgscalr-lib-4.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/imgscalr-lib-4.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/xmlbeans-2.6.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/xmlbeans-2.6.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/common-io-3.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/common-io-3.2.jar</binary-origin>
|
||||
@ -764,12 +760,12 @@
|
||||
<binary-origin>release/modules/ext/joda-time-2.4-javadoc.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jcalendarbutton-1.4.6.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jcalendarbutton-1.4.6.jar</binary-origin>
|
||||
<runtime-relative-path>ext/poi-excelant-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-excelant-3.15.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/poi-ooxml-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-ooxml-3.15.jar</binary-origin>
|
||||
<runtime-relative-path>ext/jcalendarbutton-1.4.6.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jcalendarbutton-1.4.6.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/imageio-psd-3.2.jar</runtime-relative-path>
|
||||
@ -779,18 +775,10 @@
|
||||
<runtime-relative-path>ext/stax-api-1.0.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/stax-api-1.0.1.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-collections4-4.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-collections4-4.1.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/servlet-api-2.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/servlet-api-2.5.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/poi-excelant-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-excelant-3.15.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/imageio-pcx-3.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/imageio-pcx-3.2.jar</binary-origin>
|
||||
@ -827,10 +815,6 @@
|
||||
<runtime-relative-path>ext/geronimo-jms_1.1_spec-1.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/geronimo-jms_1.1_spec-1.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/poi-scratchpad-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-scratchpad-3.15.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/joda-time-2.4-sources.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/joda-time-2.4-sources.jar</binary-origin>
|
||||
@ -839,14 +823,26 @@
|
||||
<runtime-relative-path>ext/jfxtras-fxml-8.0-r4.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jfxtras-fxml-8.0-r4.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/poi-ooxml-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-ooxml-3.15.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/joda-time-2.4.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/joda-time-2.4.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-collections4-4.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-collections4-4.1.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-logging-1.1.2-javadoc.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-logging-1.1.2-javadoc.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-codec-1.10.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-codec-1.10.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<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>
|
||||
@ -855,6 +851,18 @@
|
||||
<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/commons-io-2.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-io-2.5.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/poi-ooxml-schemas-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-ooxml-schemas-3.15.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/poi-scratchpad-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-scratchpad-3.15.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>
|
||||
@ -879,10 +887,6 @@
|
||||
<runtime-relative-path>ext/ant-1.8.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/ant-1.8.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-codec-1.10.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-codec-1.10.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/javassist-3.12.1.GA.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/javassist-3.12.1.GA.jar</binary-origin>
|
||||
@ -895,14 +899,6 @@
|
||||
<runtime-relative-path>ext/commons-logging-1.1.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-logging-1.1.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-io-2.4.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-io-2.4.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/poi-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-3.15.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/controlsfx-8.40.11.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/controlsfx-8.40.11.jar</binary-origin>
|
||||
@ -915,6 +911,10 @@
|
||||
<runtime-relative-path>ext/javaee-api-5.0-2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/javaee-api-5.0-2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/poi-3.15.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/poi-3.15.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/common-image-3.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/common-image-3.2.jar</binary-origin>
|
||||
|
@ -4,4 +4,4 @@ OpenIDE-Module: org.sleuthkit.autopsy.experimental
|
||||
OpenIDE-Module-Layer: org/sleuthkit/autopsy/experimental/autoingest/layer.xml
|
||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
|
||||
OpenIDE-Module-Requires: org.openide.windows.WindowManager
|
||||
OpenIDE-Module-Specification-Version: 1.0
|
||||
OpenIDE-Module-Specification-Version: 1.0
|
@ -167,4 +167,4 @@
|
||||
</class-path-extension>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
||||
</project>
|
@ -145,6 +145,29 @@
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
<Component class="javax.swing.JButton" name="bnCancelJob">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnCancelJob.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnCancelJob.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnDeleteCase">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnDeleteCase.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnDeleteCase.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
>>>>>>> upstream/develop
|
||||
<Component class="javax.swing.JLabel" name="lbPending">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
@ -181,6 +204,7 @@
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.refreshButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<<<<<<< HEAD
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.refreshButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
@ -188,6 +212,119 @@
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
||||
</Events>
|
||||
=======
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnRefresh.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnCancelModule">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnCancelModule.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnCancelModule.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnExit">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnExit.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnExit.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnOptions">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnOptions.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnOptions.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnShowProgress">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnShowProgress.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnShowProgress.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnPause">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnPause.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnPause.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnPrioritizeCase">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnPrioritizeCase.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnPrioritizeCase.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnShowCaseLog">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnShowCaseLog.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnShowCaseLog.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tbStatusMessage">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="12" style="1"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.tbStatusMessage.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbStatus">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="14" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.lbStatus.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnPrioritizeJob">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnPrioritizeJob.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnPrioritizeJob.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnPrioritizeJob.actionCommand" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
>>>>>>> upstream/develop
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbServicesStatus">
|
||||
<Properties>
|
||||
@ -218,14 +355,26 @@
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.prioritizeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<<<<<<< HEAD
|
||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.prioritizeButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
=======
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="bnReprocessJob">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnReprocessJob.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
>>>>>>> upstream/develop
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<<<<<<< HEAD
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="prioritizeButtonActionPerformed"/>
|
||||
</Events>
|
||||
=======
|
||||
>>>>>>> upstream/develop
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
</Form>
|
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import java.awt.Color;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.EventQueue;
|
||||
import java.nio.file.Path;
|
||||
@ -743,7 +744,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
||||
}
|
||||
}//GEN-LAST:event_prioritizeButtonActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// Variables declaration - do not modify
|
||||
private javax.swing.JScrollPane completedScrollPane;
|
||||
private javax.swing.JTable completedTable;
|
||||
private javax.swing.JLabel lbCompleted;
|
||||
@ -757,7 +758,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
||||
private javax.swing.JScrollPane runningScrollPane;
|
||||
private javax.swing.JTable runningTable;
|
||||
private javax.swing.JTextField tbServicesStatusMessage;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
// End of variables declaration
|
||||
|
||||
/*
|
||||
* The enum is used in conjunction with the DefaultTableModel class to
|
||||
|
@ -25,4 +25,8 @@
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<<<<<<< HEAD
|
||||
</Form>
|
||||
=======
|
||||
</Form>
|
||||
>>>>>>> upstream/develop
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 - 2017 Basis Technology Corp.
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,24 +18,18 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.netbeans.api.settings.ConvertAsProperties;
|
||||
import org.openide.awt.ActionID;
|
||||
import org.openide.awt.ActionReference;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.windows.TopComponent;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.Mode;
|
||||
import org.openide.windows.TopComponent;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* Top component which displays the Auto Ingest Dashboard interface.
|
||||
*/
|
||||
@ConvertAsProperties(
|
||||
dtd = "-//org.sleuthkit.autopsy.experimental.autoingest//AutoIngestDashboard//EN",
|
||||
autostore = false
|
||||
)
|
||||
@TopComponent.Description(
|
||||
preferredID = "AutoIngestDashboardTopComponent",
|
||||
//iconBase="SET/PATH/TO/ICON/HERE",
|
||||
@ -44,13 +38,11 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@TopComponent.Registration(mode = "dashboard", openAtStartup = false)
|
||||
@Messages({
|
||||
"CTL_AutoIngestDashboardAction=Auto Ingest Dashboard",
|
||||
"CTL_AutoIngestDashboardTopComponent=Auto Ingest Dashboard",
|
||||
"HINT_AutoIngestDashboardTopComponent=This is an Auto Ingest Dashboard window"
|
||||
})
|
||||
"CTL_AutoIngestDashboardTopComponent=Auto Ingest Dashboard"})
|
||||
public final class AutoIngestDashboardTopComponent extends TopComponent {
|
||||
|
||||
public final static String PREFERRED_ID = "AutoIngestDashboardTopComponent"; // NON-NLS
|
||||
private static final Logger LOGGER = Logger.getLogger(AutoIngestDashboardTopComponent.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(AutoIngestDashboardTopComponent.class.getName());
|
||||
private static boolean topComponentInitialized = false;
|
||||
|
||||
public static void openTopComponent() {
|
||||
@ -68,8 +60,11 @@ public final class AutoIngestDashboardTopComponent extends TopComponent {
|
||||
dashboard = AutoIngestDashboard.createDashboard();
|
||||
tc.add(dashboard);
|
||||
dashboard.setSize(dashboard.getPreferredSize());
|
||||
if (tc.isOpened() == false) {
|
||||
tc.open();
|
||||
tc.requestActive();
|
||||
}
|
||||
tc.toFront();
|
||||
tc.requestActive();
|
||||
} catch (AutoIngestDashboard.AutoIngestDashboardException ex) {
|
||||
// DLG: Catch the exeption, log it, and pop up an error dialog
|
||||
// with a user-friendly message
|
||||
@ -79,12 +74,12 @@ public final class AutoIngestDashboardTopComponent extends TopComponent {
|
||||
|
||||
public static void closeTopComponent() {
|
||||
if (topComponentInitialized) {
|
||||
final TopComponent etc = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
|
||||
if (etc != null) {
|
||||
final TopComponent tc = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
|
||||
if (tc != null) {
|
||||
try {
|
||||
etc.close();
|
||||
tc.close();
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.SEVERE, "failed to close " + PREFERRED_ID, e); // NON-NLS
|
||||
logger.log(Level.SEVERE, "Failed to close " + PREFERRED_ID, e); // NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,7 +88,23 @@ public final class AutoIngestDashboardTopComponent extends TopComponent {
|
||||
public AutoIngestDashboardTopComponent() {
|
||||
initComponents();
|
||||
setName(Bundle.CTL_AutoIngestDashboardTopComponent());
|
||||
setToolTipText(Bundle.HINT_AutoIngestDashboardTopComponent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Mode> availableModes(List<Mode> modes) {
|
||||
/*
|
||||
* This looks like the right thing to do, but online discussions seems
|
||||
* to indicate this method is effectively deprecated. A break point
|
||||
* placed here was never hit.
|
||||
*/
|
||||
return modes.stream().filter(mode -> mode.getName().equals("dashboard") || mode.getName().equals("ImageGallery"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentOpened() {
|
||||
super.componentOpened();
|
||||
WindowManager.getDefault().setTopComponentFloating(this, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,25 +129,5 @@ public final class AutoIngestDashboardTopComponent extends TopComponent {
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
@Override
|
||||
public void componentOpened() {
|
||||
// TODO add custom code on component opening
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentClosed() {
|
||||
// TODO add custom code on component closing
|
||||
}
|
||||
|
||||
void writeProperties(java.util.Properties p) {
|
||||
// better to version settings since initial version as advocated at
|
||||
// http://wiki.apidesign.org/wiki/PropertyFiles
|
||||
p.setProperty("version", "1.0");
|
||||
// TODO store your settings
|
||||
}
|
||||
|
||||
void readProperties(java.util.Properties p) {
|
||||
String version = p.getProperty("version");
|
||||
// TODO read your settings according to their version
|
||||
}
|
||||
}
|
||||
|
@ -2646,8 +2646,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
||||
* back into hostNamesToRunningJobs as a result of
|
||||
* processing the job status update.
|
||||
*/
|
||||
SYS_LOGGER.log(Level.WARNING, "Auto ingest node {0} timed out while processing folder {1}",
|
||||
new Object[]{job.getNodeName(), job.getNodeData().getManifestFilePath().toString()});
|
||||
hostNamesToRunningJobs.remove(job.getNodeName());
|
||||
setChanged();
|
||||
notifyObservers(Event.JOB_COMPLETED);
|
||||
|
@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
*/
|
||||
final class AutoIngestSystemLogger {
|
||||
|
||||
private static final int LOG_SIZE = 10000000; // In bytes, zero is unlimited, set to roughly 10mb currently
|
||||
private static final int LOG_SIZE = 50000000; // In bytes, zero is unlimited, set to roughly 10mb currently
|
||||
private static final int LOG_FILE_COUNT = 10;
|
||||
private static final Logger LOGGER = Logger.getLogger("AutoIngest"); //NON-NLS
|
||||
private static final String NEWLINE = System.lineSeparator();
|
||||
|
@ -305,9 +305,13 @@ AutoIngestControlPanel.lbServicesStatus.text=Services Status:
|
||||
AutoIngestControlPanel.bnPrioritizeJob.actionCommand=<AutoIngestDashboard.bnPrioritizeJob.text>
|
||||
AutoIngestControlPanel.bnPrioritizeJob.toolTipText=Move this folder to the top of the Pending queue.
|
||||
AutoIngestControlPanel.bnPrioritizeJob.text=Prioritize Job
|
||||
<<<<<<< HEAD
|
||||
AutoIngestControlPanel.lbStatus.text=Status:
|
||||
AutoIngestControlPanel.PauseDueToSystemError=Paused due to system error, please consult the auto ingest system log
|
||||
AutoIngestDashboard.prioritizeButton.toolTipText=Prioritizes the selected job
|
||||
AutoIngestDashboard.prioritizeButton.text=&Prioritize
|
||||
AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables
|
||||
AutoIngestDashboard.refreshButton.text=&Refresh
|
||||
=======
|
||||
AutoIngestControlPanel.lbStatus.text=Status:
|
||||
>>>>>>> upstream/develop
|
||||
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mode version="2.4">
|
||||
<name unique="dashboard"/>
|
||||
<kind type="editor"/>
|
||||
<state type="separated"/>
|
||||
<bounds x="76" y="68" width="996" height="672"/>
|
||||
<frame state="0"/>
|
||||
|
||||
<empty-behavior permanent="false"/>
|
||||
</mode>
|
@ -31,5 +31,11 @@
|
||||
</file>
|
||||
</folder>
|
||||
</folder>
|
||||
|
||||
<folder name="Windows2">
|
||||
<folder name="Modes">
|
||||
<file name="dashboard.wsmode" url="dashboardWsmode.xml"/>
|
||||
</folder>
|
||||
</folder>
|
||||
|
||||
</filesystem>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -73,7 +73,7 @@ class AccountsText implements IndexedText {
|
||||
private final long solrObjectId;
|
||||
private final Collection<? extends BlackboardArtifact> artifacts;
|
||||
private final Set<String> accountNumbers = new HashSet<>();
|
||||
private final String displayName;
|
||||
private final String title;
|
||||
|
||||
@GuardedBy("this")
|
||||
private boolean isPageInfoLoaded = false;
|
||||
@ -105,7 +105,7 @@ class AccountsText implements IndexedText {
|
||||
AccountsText(long objectID, Collection<? extends BlackboardArtifact> artifacts) {
|
||||
this.solrObjectId = objectID;
|
||||
this.artifacts = artifacts;
|
||||
displayName = artifacts.size() == 1
|
||||
title = artifacts.size() == 1
|
||||
? Bundle.AccountsText_creditCardNumber()
|
||||
: Bundle.AccountsText_creditCardNumbers();
|
||||
}
|
||||
@ -227,11 +227,17 @@ class AccountsText implements IndexedText {
|
||||
}
|
||||
|
||||
//add both the canonical form and the form in the text as accountNumbers to highlight.
|
||||
this.accountNumbers.add(artifact.getAttribute(TSK_KEYWORD).getValueString());
|
||||
this.accountNumbers.add(artifact.getAttribute(TSK_CARD_NUMBER).getValueString());
|
||||
BlackboardAttribute attribute = artifact.getAttribute(TSK_KEYWORD);
|
||||
if (attribute != null) {
|
||||
this.accountNumbers.add(attribute.getValueString());
|
||||
}
|
||||
attribute = artifact.getAttribute(TSK_CARD_NUMBER);
|
||||
if (attribute != null) {
|
||||
this.accountNumbers.add(attribute.getValueString());
|
||||
}
|
||||
|
||||
//if the chunk id is present just use that.
|
||||
Optional<Integer> chunkID =
|
||||
Optional<Integer> chunkID =
|
||||
Optional.ofNullable(artifact.getAttribute(TSK_KEYWORD_SEARCH_DOCUMENT_ID))
|
||||
.map(BlackboardAttribute::getValueString)
|
||||
.map(String::trim)
|
||||
@ -245,10 +251,10 @@ class AccountsText implements IndexedText {
|
||||
needsQuery = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (needsQuery) {
|
||||
// Run a query to figure out which chunks for the current object have hits.
|
||||
Keyword queryKeyword = new Keyword(CCN_REGEX, false, false);
|
||||
Keyword queryKeyword = new Keyword(CCN_REGEX, false, false);
|
||||
KeywordSearchQuery chunksQuery = KeywordSearchUtil.getQueryForKeyword(queryKeyword, new KeywordList(Arrays.asList(queryKeyword)));
|
||||
chunksQuery.addFilter(new KeywordQueryFilter(KeywordQueryFilter.FilterType.CHUNK, this.solrObjectId));
|
||||
//load the chunks/pages from the result of the query.
|
||||
@ -353,7 +359,7 @@ class AccountsText implements IndexedText {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayName;
|
||||
return title;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,7 +60,6 @@ AbstractKeywordSearchPerformer.search.ingestInProgressBody=<html>Keyword Search
|
||||
AbstractKeywordSearchPerformer.search.emptyKeywordErrorBody=Keyword list is empty, please add at least one keyword to the list
|
||||
AbstractKeywordSearchPerformer.search.noFilesInIdxMsg=<html>No files are in index yet. <br />Try again later. Index is updated every {0} minutes.</html>
|
||||
AbstractKeywordSearchPerformer.search.noFilesIdxdMsg=<html>No files were indexed.<br />Re-ingest the image with the Keyword Search Module enabled. </html>
|
||||
ExtractedContentPanel.setMarkup.panelTxt=<span style\='font-style\:italic'>Loading text... Please wait</span>
|
||||
ExtractedContentViewer.toolTip=Displays extracted text from files and keyword-search results. Requires Keyword Search ingest to be run on a file to activate this viewer.
|
||||
ExtractedContentViewer.getTitle=Indexed Text
|
||||
ExtractedContentViewer.getSolrContent.knownFileMsg=<p style\=''font-style\:italic''>{0} is a known file (based on MD5 hash) and does not have text in the index.</p>
|
||||
@ -161,8 +160,6 @@ DropdownSearchPanel.copyMenuItem.text=Copy
|
||||
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}
|
||||
ExtractedContentPanel.SetMarkup.progress.loading=Loading text
|
||||
ExtractedContentPanel.SetMarkup.progress.displayName=Loading text
|
||||
ExtractedContentViewer.nextPage.exception.msg=No next page.
|
||||
ExtractedContentViewer.previousPage.exception.msg=No previous page.
|
||||
ExtractedContentViewer.hasNextItem.exception.msg=Not supported, not a searchable source.
|
||||
|
@ -23,6 +23,7 @@ import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.EnumSet;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.PopupMenuEvent;
|
||||
@ -76,7 +77,7 @@ class DropdownToolbar extends javax.swing.JPanel {
|
||||
private void customizeComponents() {
|
||||
searchSettingsChangeListener = new SearchSettingsChangeListener();
|
||||
KeywordSearch.getServer().addServerActionListener(searchSettingsChangeListener);
|
||||
Case.addPropertyChangeListener(searchSettingsChangeListener);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), searchSettingsChangeListener);
|
||||
|
||||
DropdownListSearchPanel listsPanel = DropdownListSearchPanel.getDefault();
|
||||
listsPanel.addSearchButtonActionListener((ActionEvent e) -> {
|
||||
|
@ -18,17 +18,15 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.awt.ComponentOrientation;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.SizeRequirements;
|
||||
import javax.swing.SwingWorker;
|
||||
@ -45,6 +43,7 @@ import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.TextUtil;
|
||||
import static org.sleuthkit.autopsy.keywordsearch.Bundle.*;
|
||||
|
||||
/**
|
||||
* Panel displays HTML content sent to ExtractedContentViewer, and provides a
|
||||
@ -52,7 +51,8 @@ import org.sleuthkit.autopsy.coreutils.TextUtil;
|
||||
*/
|
||||
class ExtractedContentPanel extends javax.swing.JPanel {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ExtractedContentPanel.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(ExtractedContentPanel.class.getName());
|
||||
private String contentName;
|
||||
|
||||
ExtractedContentPanel() {
|
||||
initComponents();
|
||||
@ -124,32 +124,17 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
||||
|
||||
extractedTextPane.setEditorKit(editorKit);
|
||||
|
||||
sourceComboBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
IndexedText source = (IndexedText) e.getItem();
|
||||
setMarkup(source);
|
||||
}
|
||||
sourceComboBox.addItemListener((ItemEvent e) -> {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
setMarkup((IndexedText) e.getItem());
|
||||
}
|
||||
});
|
||||
|
||||
setSources(new ArrayList<IndexedText>());
|
||||
setSources("",new ArrayList<>());
|
||||
|
||||
extractedTextPane.setComponentPopupMenu(rightClickMenu);
|
||||
ActionListener actList = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem jmi = (JMenuItem) e.getSource();
|
||||
if (jmi.equals(copyMenuItem)) {
|
||||
extractedTextPane.copy();
|
||||
} else if (jmi.equals(selectAllMenuItem)) {
|
||||
extractedTextPane.selectAll();
|
||||
}
|
||||
}
|
||||
};
|
||||
copyMenuItem.addActionListener(actList);
|
||||
selectAllMenuItem.addActionListener(actList);
|
||||
copyMenuItem.addActionListener(actionEvent -> extractedTextPane.copy());
|
||||
selectAllMenuItem.addActionListener(actionEvent -> extractedTextPane.selectAll());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -364,8 +349,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
void refreshCurrentMarkup() {
|
||||
IndexedText ms = (IndexedText) sourceComboBox.getSelectedItem();
|
||||
setMarkup(ms);
|
||||
setMarkup(getSelectedSource());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -374,13 +358,12 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
||||
*
|
||||
* @param sources
|
||||
*/
|
||||
void setSources(List<IndexedText> sources) {
|
||||
void setSources(String contentName, List<IndexedText> sources) {
|
||||
this.contentName = contentName;
|
||||
sourceComboBox.removeAllItems();
|
||||
setPanelText(null, false);
|
||||
|
||||
for (IndexedText ms : sources) {
|
||||
sourceComboBox.addItem(ms);
|
||||
}
|
||||
sources.forEach(sourceComboBox::addItem);
|
||||
|
||||
if (!sources.isEmpty()) {
|
||||
sourceComboBox.setSelectedIndex(0);
|
||||
@ -411,9 +394,8 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
private void setPanelText(String text, boolean detectDirection) {
|
||||
if (text == null) {
|
||||
text = "";
|
||||
}
|
||||
|
||||
text = Strings.nullToEmpty(text);
|
||||
|
||||
if (detectDirection) {
|
||||
//detect text direction using first 1024 chars and set it
|
||||
@ -640,9 +622,10 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
||||
* text). Updates GUI in GUI thread and gets markup in background thread. To
|
||||
* be invoked from GUI thread only.
|
||||
*/
|
||||
@NbBundle.Messages("ExtractedContentPanel.setMarkup.panelTxt=<span style='font-style:italic'>Loading text... Please wait</span>")
|
||||
private void setMarkup(IndexedText source) {
|
||||
setPanelText(NbBundle.getMessage(this.getClass(), "ExtractedContentPanel.setMarkup.panelTxt"), false);
|
||||
new SetMarkupWorker(source).execute();
|
||||
setPanelText(ExtractedContentPanel_setMarkup_panelTxt(), false);
|
||||
new SetMarkupWorker(contentName,source).execute();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -652,18 +635,21 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
||||
*/
|
||||
private final class SetMarkupWorker extends SwingWorker<String, Void> {
|
||||
|
||||
private final String contentName;
|
||||
|
||||
private final IndexedText source;
|
||||
|
||||
private ProgressHandle progress;
|
||||
|
||||
SetMarkupWorker(IndexedText source) {
|
||||
SetMarkupWorker(String contentName,IndexedText source) {
|
||||
this.contentName = contentName;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages({"# 0 - Content name","ExtractedContentPanel.SetMarkup.progress.loading=Loading text for {0}"})
|
||||
protected String doInBackground() throws Exception {
|
||||
progress = ProgressHandle.createHandle(NbBundle.getMessage(this.getClass(), "ExtractedContentPanel.SetMarkup.progress.loading"));
|
||||
progress.setDisplayName(NbBundle.getMessage(this.getClass(), "ExtractedContentPanel.SetMarkup.progress.displayName"));
|
||||
progress = ProgressHandle.createHandle(ExtractedContentPanel_SetMarkup_progress_loading(contentName));
|
||||
progress.start();
|
||||
progress.switchToIndeterminate();
|
||||
|
||||
|
@ -27,13 +27,13 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
|
||||
@ -91,7 +91,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
||||
}
|
||||
|
||||
Lookup nodeLookup = node.getLookup();
|
||||
Content content = nodeLookup.lookup(Content.class);
|
||||
AbstractFile content = nodeLookup.lookup(AbstractFile.class);
|
||||
|
||||
/*
|
||||
* Assemble a collection of all of the indexed text "sources" for the
|
||||
@ -173,7 +173,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
||||
}
|
||||
}
|
||||
panel.updateControls(currentSource);
|
||||
setPanel(sources);
|
||||
setPanel(content.getName(),sources);
|
||||
}
|
||||
|
||||
static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException {
|
||||
@ -254,7 +254,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
||||
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
setPanel(new ArrayList<>());
|
||||
setPanel("",new ArrayList<>());
|
||||
panel.resetDisplay();
|
||||
currentNode = null;
|
||||
currentSource = null;
|
||||
@ -312,9 +312,10 @@ public class ExtractedContentViewer implements DataContentViewer {
|
||||
*
|
||||
* @param sources
|
||||
*/
|
||||
private void setPanel(List<IndexedText> sources) {
|
||||
private void setPanel(String contentName, List<IndexedText> sources) {
|
||||
|
||||
if (panel != null) {
|
||||
panel.setSources(sources);
|
||||
panel.setSources(contentName, sources);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,6 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* Interface to provide HTML text to display in ExtractedContentViewer. There is
|
||||
* a SOLR implementation of this that interfaces with SOLR to highlight the
|
||||
@ -138,4 +136,5 @@ interface IndexedText {
|
||||
* @return the current item number
|
||||
*/
|
||||
int currentItem();
|
||||
|
||||
}
|
||||
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 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 java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
|
||||
/**
|
||||
* result of writing keyword search result to blackboard (cached artifact and
|
||||
* attributes) This is mainly to cache the attributes, so that we don't query
|
||||
* the DB to get them back again.
|
||||
*/
|
||||
class KeywordCachedArtifact {
|
||||
|
||||
private BlackboardArtifact artifact;
|
||||
private Map<Integer, BlackboardAttribute> attributes;
|
||||
|
||||
KeywordCachedArtifact(BlackboardArtifact artifact) {
|
||||
this.artifact = artifact;
|
||||
attributes = new HashMap<Integer, BlackboardAttribute>();
|
||||
}
|
||||
|
||||
BlackboardArtifact getArtifact() {
|
||||
return artifact;
|
||||
}
|
||||
|
||||
Collection<BlackboardAttribute> getAttributes() {
|
||||
return attributes.values();
|
||||
}
|
||||
|
||||
BlackboardAttribute getAttribute(Integer attrTypeID) {
|
||||
return attributes.get(attrTypeID);
|
||||
}
|
||||
|
||||
void add(BlackboardAttribute attribute) {
|
||||
attributes.put(attribute.getAttributeType().getTypeID(), attribute);
|
||||
}
|
||||
|
||||
void add(Collection<BlackboardAttribute> attributes) {
|
||||
for (BlackboardAttribute attr : attributes) {
|
||||
this.attributes.put(attr.getAttributeType().getTypeID(), attr);
|
||||
}
|
||||
}
|
||||
}
|
@ -18,17 +18,18 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import java.util.Comparator;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Stores the fact that file or an artifact associated with a file had a keyword
|
||||
* hit. All instances make both the document id of the Solr document where the
|
||||
* keyword was found and the file available to clients. Artifact keyword hits
|
||||
* also make the artifact available to clients.
|
||||
* keyword was found and the object Id available to clients. Artifact keyword
|
||||
* hits also make the artifact available to clients.
|
||||
*/
|
||||
class KeywordHit implements Comparable<KeywordHit> {
|
||||
|
||||
@ -36,7 +37,7 @@ class KeywordHit implements Comparable<KeywordHit> {
|
||||
private final long solrObjectId;
|
||||
private final int chunkId;
|
||||
private final String snippet;
|
||||
private final Content content;
|
||||
private final long contentID;
|
||||
private final BlackboardArtifact artifact;
|
||||
private final String hit;
|
||||
|
||||
@ -44,14 +45,9 @@ class KeywordHit implements Comparable<KeywordHit> {
|
||||
return hit;
|
||||
}
|
||||
|
||||
KeywordHit(String solrDocumentId, String snippet) throws TskCoreException {
|
||||
this(solrDocumentId, snippet, null);
|
||||
}
|
||||
|
||||
KeywordHit(String solrDocumentId, String snippet, String hit) throws TskCoreException {
|
||||
/**
|
||||
* Store the Solr document id.
|
||||
*/
|
||||
this.snippet = StringUtils.stripToEmpty(snippet);
|
||||
this.hit = hit;
|
||||
this.solrDocumentId = solrDocumentId;
|
||||
|
||||
/**
|
||||
@ -72,27 +68,19 @@ class KeywordHit implements Comparable<KeywordHit> {
|
||||
this.chunkId = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the file associated with the keyword hit. If the high order
|
||||
* bit of the object id is set, the hit was for an artifact. In this
|
||||
* case, look up the artifact as well.
|
||||
/*
|
||||
* If the high order bit of the object id is set (ie, it is negative),
|
||||
* the hit was in an artifact, look up the artifact.
|
||||
*/
|
||||
SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase();
|
||||
long fileId;
|
||||
if (this.solrObjectId < 0) {
|
||||
SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase();
|
||||
this.artifact = caseDb.getBlackboardArtifact(this.solrObjectId);
|
||||
fileId = artifact.getObjectID();
|
||||
contentID = artifact.getObjectID();
|
||||
} else {
|
||||
//else the object id is for content.
|
||||
this.artifact = null;
|
||||
fileId = this.solrObjectId;
|
||||
contentID = this.solrObjectId;
|
||||
}
|
||||
this.content = caseDb.getContentById(fileId);
|
||||
|
||||
/**
|
||||
* Store the text snippet.
|
||||
*/
|
||||
this.snippet = snippet;
|
||||
this.hit = hit;
|
||||
}
|
||||
|
||||
String getSolrDocumentId() {
|
||||
@ -103,24 +91,20 @@ class KeywordHit implements Comparable<KeywordHit> {
|
||||
return this.solrObjectId;
|
||||
}
|
||||
|
||||
boolean hasChunkId() {
|
||||
return this.chunkId != 0;
|
||||
}
|
||||
|
||||
int getChunkId() {
|
||||
return this.chunkId;
|
||||
}
|
||||
|
||||
boolean hasSnippet() {
|
||||
return !this.snippet.isEmpty();
|
||||
return StringUtils.isNotBlank(this.snippet);
|
||||
}
|
||||
|
||||
String getSnippet() {
|
||||
return this.snippet;
|
||||
}
|
||||
|
||||
Content getContent() {
|
||||
return this.content;
|
||||
long getContentID() {
|
||||
return this.contentID;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -151,7 +135,7 @@ class KeywordHit implements Comparable<KeywordHit> {
|
||||
return false;
|
||||
}
|
||||
final KeywordHit other = (KeywordHit) obj;
|
||||
return (this.solrObjectId == other.solrObjectId && this.chunkId == other.chunkId);
|
||||
return this.compareTo(other) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -163,21 +147,8 @@ class KeywordHit implements Comparable<KeywordHit> {
|
||||
|
||||
@Override
|
||||
public int compareTo(KeywordHit o) {
|
||||
if (this.solrObjectId < o.solrObjectId) {
|
||||
// Out object id is less than the other object id
|
||||
return -1;
|
||||
} else if (this.solrObjectId == o.solrObjectId) {
|
||||
// Hits have same object id
|
||||
if (this.chunkId < o.chunkId) {
|
||||
// Our chunk id is lower than the other chunk id
|
||||
return -1;
|
||||
} else {
|
||||
// Our chunk id is either greater than or equal to the other chunk id
|
||||
return this.chunkId == o.chunkId ? 0 : 1;
|
||||
}
|
||||
} else {
|
||||
// Our object id is greater than the other object id
|
||||
return 1;
|
||||
}
|
||||
return Comparator.comparing(KeywordHit::getSolrObjectId)
|
||||
.thenComparing(KeywordHit::getChunkId)
|
||||
.compare(this, o);
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,11 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* Interface for kewyord search queries.
|
||||
* Interface for kewyord search queries.
|
||||
*/
|
||||
interface KeywordSearchQuery {
|
||||
|
||||
@ -30,18 +33,20 @@ interface KeywordSearchQuery {
|
||||
*
|
||||
* @return true if the query passed validation
|
||||
*/
|
||||
boolean validate();
|
||||
boolean validate();
|
||||
|
||||
/**
|
||||
* execute query and return results without publishing them return results
|
||||
* for all matching terms
|
||||
*
|
||||
* @throws KeywordSearchModuleException error while executing Solr term query
|
||||
* @throws NoOpenCoreException if query failed due to server error, this
|
||||
* could be a notification to stop processing
|
||||
* @throws KeywordSearchModuleException error while executing Solr term
|
||||
* query
|
||||
* @throws NoOpenCoreException if query failed due to server error,
|
||||
* this could be a notification to stop
|
||||
* processing
|
||||
* @return
|
||||
*/
|
||||
QueryResults performQuery() throws KeywordSearchModuleException, NoOpenCoreException;
|
||||
QueryResults performQuery() throws KeywordSearchModuleException, NoOpenCoreException;
|
||||
|
||||
/**
|
||||
* Set an optional filter to narrow down the search Adding multiple filters
|
||||
@ -49,54 +54,67 @@ interface KeywordSearchQuery {
|
||||
*
|
||||
* @param filter filter to set on the query
|
||||
*/
|
||||
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
|
||||
*/
|
||||
void setField(String field);
|
||||
void setField(String field);
|
||||
|
||||
/**
|
||||
* Modify the query string to be searched as a substring instead of a whole
|
||||
* word
|
||||
*
|
||||
* @param isSubstring
|
||||
*/
|
||||
void setSubstringQuery();
|
||||
void setSubstringQuery();
|
||||
|
||||
/**
|
||||
* escape the query string and use the escaped string in the query
|
||||
*/
|
||||
void escape();
|
||||
void escape();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if query was escaped
|
||||
*/
|
||||
boolean isEscaped();
|
||||
boolean isEscaped();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if query is a literal query (non regex)
|
||||
*/
|
||||
boolean isLiteral();
|
||||
boolean isLiteral();
|
||||
|
||||
/**
|
||||
* return original keyword/query string
|
||||
*
|
||||
* @return the query String supplied originally
|
||||
*/
|
||||
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
|
||||
*/
|
||||
String getEscapedQueryString();
|
||||
|
||||
KeywordCachedArtifact writeSingleFileHitsToBlackBoard(Keyword keyword, KeywordHit hit, String snippet, String listName);
|
||||
String getEscapedQueryString();
|
||||
|
||||
/**
|
||||
* Converts the keyword hits for a given search term into artifacts.
|
||||
*
|
||||
* @param content The Content object associated with the hit.
|
||||
* @param foundKeyword The keyword that was found by the search, this may be
|
||||
* different than the Keyword that was searched if, for
|
||||
* example, it was a RegexQuery.
|
||||
* @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 The newly created artifact or Null if there was a problem
|
||||
* creating it.
|
||||
*/
|
||||
BlackboardArtifact writeSingleFileHitsToBlackBoard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName);
|
||||
}
|
||||
|
@ -18,13 +18,10 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import com.google.common.collect.SetMultimap;
|
||||
import com.google.common.collect.TreeMultimap;
|
||||
import java.awt.EventQueue;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@ -41,6 +38,7 @@ import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
||||
@ -50,12 +48,13 @@ import org.sleuthkit.autopsy.datamodel.KeyValue;
|
||||
import org.sleuthkit.autopsy.datamodel.KeyValueNode;
|
||||
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.KeyValueQueryContent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Node factory that performs the keyword search and creates children nodes for
|
||||
@ -69,16 +68,16 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
||||
private static final Logger logger = Logger.getLogger(KeywordSearchResultFactory.class.getName());
|
||||
|
||||
//common properties (superset of all Node properties) to be displayed as columns
|
||||
static final List<String> COMMON_PROPERTIES
|
||||
= Stream.concat(
|
||||
static final List<String> COMMON_PROPERTIES =
|
||||
Stream.concat(
|
||||
Stream.of(
|
||||
TSK_KEYWORD,
|
||||
TSK_KEYWORD_REGEXP,
|
||||
TSK_KEYWORD_PREVIEW)
|
||||
.map(BlackboardAttribute.ATTRIBUTE_TYPE::getDisplayName),
|
||||
.map(BlackboardAttribute.ATTRIBUTE_TYPE::getDisplayName),
|
||||
Arrays.stream(AbstractAbstractFileNode.AbstractFilePropertyType.values())
|
||||
.map(Object::toString))
|
||||
.collect(Collectors.toList());
|
||||
.map(Object::toString))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
private final Collection<QueryRequest> queryRequests;
|
||||
|
||||
@ -91,7 +90,7 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
||||
* properties are displayed as columns (since we are doing lazy child Node
|
||||
* load we need to preinitialize properties when sending parent Node)
|
||||
*
|
||||
* @param toSet property set map for a Node
|
||||
* @param toPopulate property set map for a Node
|
||||
*/
|
||||
@Override
|
||||
protected boolean createKeys(List<KeyValueQueryContent> toPopulate) {
|
||||
@ -144,6 +143,13 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
||||
MessageNotifyUtil.Notify.error(Bundle.KeywordSearchResultFactory_query_exception_msg() + queryRequest.getQueryString(), ex.getCause().getMessage());
|
||||
return false;
|
||||
}
|
||||
SleuthkitCase tskCase = null;
|
||||
try {
|
||||
tskCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
} catch (IllegalStateException ex) {
|
||||
logger.log(Level.SEVERE, "There was no case open.", ex); //NON-NLS
|
||||
return false;
|
||||
}
|
||||
|
||||
int hitNumber = 0;
|
||||
List<KeyValueQueryContent> tempList = new ArrayList<>();
|
||||
@ -153,8 +159,20 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
||||
* Get file properties.
|
||||
*/
|
||||
Map<String, Object> properties = new LinkedHashMap<>();
|
||||
Content content = hit.getContent();
|
||||
String contentName = content.getName();
|
||||
Content content = null;
|
||||
String contentName = "";
|
||||
try {
|
||||
content = tskCase.getContentById(hit.getContentID());
|
||||
if (content == null) {
|
||||
logger.log(Level.SEVERE, "There was a error getting content by id."); //NON-NLS
|
||||
return false;
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "There was a error getting content by id.", ex); //NON-NLS
|
||||
return false;
|
||||
}
|
||||
|
||||
contentName = content.getName();
|
||||
if (content instanceof AbstractFile) {
|
||||
AbstractFsContentNode.fillPropertyMap(properties, (AbstractFile) content);
|
||||
} else {
|
||||
@ -222,6 +240,7 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
||||
|
||||
//wrap in KeywordSearchFilterNode for the markup content, might need to override FilterNode for more customization
|
||||
return new KeywordSearchFilterNode(hits, kvNode);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -240,13 +259,14 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
||||
* NOTE Parameters are defined based on how they are currently used in
|
||||
* practice
|
||||
*
|
||||
* @param name File name that has hit.
|
||||
* @param map Contains content metadata, snippets, etc. (property
|
||||
* map)
|
||||
* @param id User incremented ID
|
||||
* @param content File that had the hit.
|
||||
* @param query Query used in search
|
||||
* @param hits Full set of search results (for all files! @@@)
|
||||
* @param name File name that has hit.
|
||||
* @param map Contains content metadata, snippets, etc.
|
||||
* (property map)
|
||||
* @param id User incremented ID
|
||||
* @param solrObjectId
|
||||
* @param content File that had the hit.
|
||||
* @param query Query used in search
|
||||
* @param hits Full set of search results (for all files! @@@)
|
||||
*/
|
||||
KeyValueQueryContent(String name, Map<String, Object> map, int id, long solrObjectId, Content content, KeywordSearchQuery query, QueryResults hits) {
|
||||
super(name, map, id);
|
||||
@ -278,13 +298,12 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
||||
* worker for writing results to bb, with progress bar, cancellation, and
|
||||
* central registry of workers to be stopped when case is closed
|
||||
*/
|
||||
static class BlackboardResultWriter extends SwingWorker<Object, Void> {
|
||||
static class BlackboardResultWriter extends SwingWorker<Void, Void> {
|
||||
|
||||
private static final List<BlackboardResultWriter> writers = new ArrayList<>();
|
||||
private ProgressHandle progress;
|
||||
private final KeywordSearchQuery query;
|
||||
private final QueryResults hits;
|
||||
private Collection<BlackboardArtifact> newArtifacts = new ArrayList<>();
|
||||
private static final int QUERY_DISPLAY_LEN = 40;
|
||||
|
||||
BlackboardResultWriter(QueryResults hits, String listName) {
|
||||
@ -298,13 +317,13 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
protected Void doInBackground() throws Exception {
|
||||
registerWriter(this); //register (synchronized on class) outside of writerLock to prevent deadlock
|
||||
final String queryStr = query.getQueryString();
|
||||
final String queryDisp = queryStr.length() > QUERY_DISPLAY_LEN ? queryStr.substring(0, QUERY_DISPLAY_LEN - 1) + " ..." : queryStr;
|
||||
try {
|
||||
progress = ProgressHandle.createHandle(NbBundle.getMessage(this.getClass(), "KeywordSearchResultFactory.progress.saving", queryDisp), () -> BlackboardResultWriter.this.cancel(true));
|
||||
newArtifacts = hits.writeAllHitsToBlackBoard(progress, null, this, false);
|
||||
hits.writeAllHitsToBlackBoard(progress, null, this, false);
|
||||
} finally {
|
||||
finalizeWorker();
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
@ -40,6 +39,7 @@ 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.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
|
||||
@ -192,15 +192,13 @@ class LuceneQuery implements KeywordSearchQuery {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeywordCachedArtifact writeSingleFileHitsToBlackBoard(Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
|
||||
public BlackboardArtifact writeSingleFileHitsToBlackBoard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
|
||||
final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
|
||||
|
||||
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||
BlackboardArtifact bba;
|
||||
KeywordCachedArtifact writeResult;
|
||||
try {
|
||||
bba = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||
writeResult = new KeywordCachedArtifact(bba);
|
||||
bba = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||
} catch (TskCoreException e) {
|
||||
logger.log(Level.WARNING, "Error adding bb artifact for keyword hit", e); //NON-NLS
|
||||
return null;
|
||||
@ -233,8 +231,7 @@ class LuceneQuery implements KeywordSearchQuery {
|
||||
|
||||
try {
|
||||
bba.addAttributes(attributes); //write out to bb
|
||||
writeResult.add(attributes);
|
||||
return writeResult;
|
||||
return bba;
|
||||
} catch (TskCoreException e) {
|
||||
logger.log(Level.WARNING, "Error adding bb attributes to artifact", e); //NON-NLS
|
||||
return null;
|
||||
|
@ -31,6 +31,7 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.netbeans.api.progress.ProgressHandle;
|
||||
import org.netbeans.api.progress.aggregate.ProgressContributor;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||
@ -40,6 +41,8 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Stores the results from running a Solr query (which could contain multiple
|
||||
@ -60,8 +63,6 @@ class QueryResults {
|
||||
*/
|
||||
private final Map<Keyword, List<KeywordHit>> results = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
QueryResults(KeywordSearchQuery query) {
|
||||
this.keywordSearchQuery = query;
|
||||
}
|
||||
@ -70,8 +71,6 @@ class QueryResults {
|
||||
results.put(keyword, hits);
|
||||
}
|
||||
|
||||
|
||||
|
||||
KeywordSearchQuery getQuery() {
|
||||
return keywordSearchQuery;
|
||||
}
|
||||
@ -99,7 +98,7 @@ class QueryResults {
|
||||
*
|
||||
* @return The artifacts that were created.
|
||||
*/
|
||||
Collection<BlackboardArtifact> writeAllHitsToBlackBoard(ProgressHandle progress, ProgressContributor subProgress, SwingWorker<Object, Void> worker, boolean notifyInbox) {
|
||||
Collection<BlackboardArtifact> writeAllHitsToBlackBoard(ProgressHandle progress, ProgressContributor subProgress, SwingWorker<?, ?> worker, boolean notifyInbox) {
|
||||
final Collection<BlackboardArtifact> newArtifacts = new ArrayList<>();
|
||||
if (progress != null) {
|
||||
progress.start(getKeywords().size());
|
||||
@ -145,14 +144,26 @@ class QueryResults {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
KeywordCachedArtifact writeResult = keywordSearchQuery.writeSingleFileHitsToBlackBoard(keyword, hit, snippet, keywordSearchQuery.getKeywordList().getName());
|
||||
Content content = null;
|
||||
try {
|
||||
SleuthkitCase tskCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
content = tskCase.getContentById(hit.getContentID());
|
||||
} catch (TskCoreException | IllegalStateException tskCoreException) {
|
||||
logger.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", tskCoreException); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
BlackboardArtifact writeResult = keywordSearchQuery.writeSingleFileHitsToBlackBoard(content, keyword, hit, snippet, keywordSearchQuery.getKeywordList().getName());
|
||||
if (writeResult != null) {
|
||||
newArtifacts.add(writeResult.getArtifact());
|
||||
newArtifacts.add(writeResult);
|
||||
if (notifyInbox) {
|
||||
writeSingleFileInboxMessage(writeResult, hit.getContent());
|
||||
try {
|
||||
writeSingleFileInboxMessage(writeResult, content);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Error posting message to Ingest Inbox", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.WARNING, "BB artifact for keyword hit not written, file: {0}, hit: {1}", new Object[]{hit.getContent(), keyword.toString()}); //NON-NLS
|
||||
logger.log(Level.WARNING, "BB artifact for keyword hit not written, file: {0}, hit: {1}", new Object[]{content, keyword.toString()}); //NON-NLS
|
||||
}
|
||||
}
|
||||
++unitProgress;
|
||||
@ -181,7 +192,6 @@ class QueryResults {
|
||||
* SolrObjectID-ChunkID pairs.
|
||||
*/
|
||||
private Collection<KeywordHit> getOneHitPerObject(Keyword keyword) {
|
||||
|
||||
HashMap<Long, KeywordHit> hits = new HashMap<>();
|
||||
|
||||
// create a list of KeywordHits. KeywordHits with lowest chunkID is added the the list.
|
||||
@ -196,12 +206,16 @@ class QueryResults {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an ingest inbox message for given keyword in given file
|
||||
* Generate and post an ingest inbox message for the given keyword in the
|
||||
* given content.
|
||||
*
|
||||
* @param written
|
||||
* @param hitFile
|
||||
* @param artifact The keyword hit artifact.
|
||||
* @param hitContent The content that the hit is in.
|
||||
*
|
||||
* @throws TskCoreException If there is a problem generating or posting the
|
||||
* inbox message.
|
||||
*/
|
||||
private void writeSingleFileInboxMessage(KeywordCachedArtifact written, Content hitContent) {
|
||||
private void writeSingleFileInboxMessage(BlackboardArtifact artifact, Content hitContent) throws TskCoreException {
|
||||
StringBuilder subjectSb = new StringBuilder();
|
||||
StringBuilder detailsSb = new StringBuilder();
|
||||
|
||||
@ -210,24 +224,24 @@ class QueryResults {
|
||||
} else {
|
||||
subjectSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.kwHitLbl"));
|
||||
}
|
||||
|
||||
String uniqueKey = null;
|
||||
BlackboardAttribute attr = written.getAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID());
|
||||
BlackboardAttribute attr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD));
|
||||
if (attr != null) {
|
||||
final String keyword = attr.getValueString();
|
||||
subjectSb.append(keyword);
|
||||
uniqueKey = keyword.toLowerCase();
|
||||
//details
|
||||
detailsSb.append("<table border='0' cellpadding='4' width='280'>"); //NON-NLS
|
||||
//hit
|
||||
detailsSb.append("<tr>"); //NON-NLS
|
||||
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.kwHitThLbl"));
|
||||
detailsSb.append("<td>").append(EscapeUtil.escapeHtml(keyword)).append("</td>"); //NON-NLS
|
||||
detailsSb.append("</tr>"); //NON-NLS
|
||||
}
|
||||
|
||||
//details
|
||||
detailsSb.append("<table border='0' cellpadding='4' width='280'>"); //NON-NLS
|
||||
//hit
|
||||
detailsSb.append("<tr>"); //NON-NLS
|
||||
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.kwHitThLbl"));
|
||||
detailsSb.append("<td>").append(EscapeUtil.escapeHtml(attr.getValueString())).append("</td>"); //NON-NLS
|
||||
detailsSb.append("</tr>"); //NON-NLS
|
||||
|
||||
//preview
|
||||
attr = written.getAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID());
|
||||
attr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW));
|
||||
if (attr != null) {
|
||||
detailsSb.append("<tr>"); //NON-NLS
|
||||
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.previewThLbl"));
|
||||
@ -247,16 +261,17 @@ class QueryResults {
|
||||
detailsSb.append("</tr>"); //NON-NLS
|
||||
|
||||
//list
|
||||
attr = written.getAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID());
|
||||
attr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
|
||||
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());
|
||||
attr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP));
|
||||
if (attr != null) {
|
||||
detailsSb.append("<tr>"); //NON-NLS
|
||||
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.regExThLbl"));
|
||||
@ -264,9 +279,9 @@ class QueryResults {
|
||||
detailsSb.append("</tr>"); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
detailsSb.append("</table>"); //NON-NLS
|
||||
|
||||
IngestServices.getInstance().postMessage(IngestMessage.createDataMessage(MODULE_NAME, subjectSb.toString(), detailsSb.toString(), uniqueKey, written.getArtifact()));
|
||||
IngestServices.getInstance().postMessage(IngestMessage.createDataMessage(MODULE_NAME, subjectSb.toString(), detailsSb.toString(), uniqueKey, artifact));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,15 +19,11 @@
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
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;
|
||||
@ -52,11 +48,9 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
|
||||
/**
|
||||
* The RegexQuery class supports issuing regular expression queries against a
|
||||
@ -87,8 +81,6 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
|
||||
private final int MIN_EMAIL_ADDR_LENGTH = 8;
|
||||
|
||||
private final ListMultimap<Keyword, KeywordHit> hitsMultiMap = ArrayListMultimap.create();
|
||||
|
||||
// Lucene regular expressions do not support the following Java predefined
|
||||
// and POSIX character classes. There are other valid Java character classes
|
||||
// that are not supported by Lucene but we do not check for all of them.
|
||||
@ -191,8 +183,9 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
solrQuery.setSort(SortClause.asc(Server.Schema.ID.toString()));
|
||||
|
||||
String cursorMark = CursorMarkParams.CURSOR_MARK_START;
|
||||
SolrDocumentList resultList ;
|
||||
SolrDocumentList resultList;
|
||||
boolean allResultsProcessed = false;
|
||||
QueryResults results = new QueryResults(this);
|
||||
|
||||
while (!allResultsProcessed) {
|
||||
try {
|
||||
@ -204,9 +197,15 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
try {
|
||||
List<KeywordHit> keywordHits = createKeywordHits(resultDoc);
|
||||
for (KeywordHit hit : keywordHits) {
|
||||
hitsMultiMap.put(new Keyword(hit.getHit(), true, true, originalKeyword.getListName(), originalKeyword.getOriginalTerm()), hit);
|
||||
Keyword keywordInstance = new Keyword(hit.getHit(), true, true, originalKeyword.getListName(), originalKeyword.getOriginalTerm());
|
||||
List<KeywordHit> hitsForKeyword = results.getResults(keywordInstance);
|
||||
if (hitsForKeyword == null) {
|
||||
hitsForKeyword = new ArrayList<>();
|
||||
results.addResult(keywordInstance, hitsForKeyword);
|
||||
}
|
||||
hitsForKeyword.add(hit);
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error creating keyword hits", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
@ -221,10 +220,7 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
MessageNotifyUtil.Notify.error(NbBundle.getMessage(Server.class, "Server.query.exception.msg", keywordString), ex.getCause().getMessage());
|
||||
}
|
||||
}
|
||||
QueryResults results = new QueryResults(this);
|
||||
for (Keyword k : hitsMultiMap.keySet()) {
|
||||
results.addResult(k, hitsMultiMap.get(k));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@ -287,8 +283,8 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
}
|
||||
|
||||
/*
|
||||
* If searching for credit card account numbers, do a Luhn check
|
||||
* on the term and discard it if it does not pass.
|
||||
* If searching for credit card account numbers, do a Luhn
|
||||
* check on the term and discard it if it does not pass.
|
||||
*/
|
||||
if (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
||||
Matcher ccnMatcher = CREDIT_CARD_NUM_PATTERN.matcher(hit);
|
||||
@ -319,10 +315,14 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
} catch (TskCoreException ex) {
|
||||
throw ex;
|
||||
} catch (Throwable error) {
|
||||
/* NOTE: Matcher.find() is known to throw StackOverflowError in rare cases (see JIRA-2700).
|
||||
StackOverflowError is an error, not an exception, and therefore needs to be caught
|
||||
as a Throwable. When this occurs we should re-throw the error as TskCoreException so that it is
|
||||
logged by the calling method and move on to the next Solr document. */
|
||||
/*
|
||||
* NOTE: Matcher.find() is known to throw StackOverflowError in rare
|
||||
* cases (see JIRA-2700). StackOverflowError is an error, not an
|
||||
* exception, and therefore needs to be caught as a Throwable. When
|
||||
* this occurs we should re-throw the error as TskCoreException so
|
||||
* that it is logged by the calling method and move on to the next
|
||||
* Solr document.
|
||||
*/
|
||||
throw new TskCoreException("Failed to create keyword hits for Solr document id " + docId + " due to " + error.getMessage());
|
||||
}
|
||||
return hits;
|
||||
@ -373,50 +373,15 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
return escapedQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a unique, comma separated list of document ids that match the given
|
||||
* hit for the same object.
|
||||
*
|
||||
* @param keyword The keyword object that resulted in one or more hits.
|
||||
* @param hit The specific hit for which we want to identify all other
|
||||
* chunks that match the keyword
|
||||
*
|
||||
* @return A comma separated list of unique document ids.
|
||||
*/
|
||||
private String getDocumentIds(Keyword keyword, KeywordHit hit) {
|
||||
Set<String> documentIds = new HashSet<>();
|
||||
|
||||
for (KeywordHit h : hitsMultiMap.get(keyword)) {
|
||||
// Add the document id only if it is for the same object as the
|
||||
// given hit and we haven't already seen it.
|
||||
if (h.getSolrObjectId() == hit.getSolrObjectId() && !documentIds.contains(h.getSolrDocumentId())) {
|
||||
documentIds.add(h.getSolrDocumentId());
|
||||
}
|
||||
}
|
||||
|
||||
return StringUtils.join(documentIds, ",");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the keyword hits for a given search term into artifacts.
|
||||
*
|
||||
* @param foundKeyword The keyword that was found by the regex search.
|
||||
* @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(Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
|
||||
public BlackboardArtifact writeSingleFileHitsToBlackBoard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
|
||||
final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
|
||||
|
||||
if (content == null) {
|
||||
LOGGER.log(Level.WARNING, "Error adding artifact for keyword hit to blackboard"); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create either a "plain vanilla" keyword hit artifact with keyword and
|
||||
* regex attributes, or a credit card account artifact with attributes
|
||||
@ -429,8 +394,7 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
|
||||
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString()));
|
||||
try {
|
||||
newArtifact = hit.getContent().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||
|
||||
newArtifact = content.newArtifact(BlackboardArtifact.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;
|
||||
@ -455,7 +419,7 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
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", foundKeyword.getSearchTerm(), 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", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContent().getId())); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContentID())); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -491,8 +455,8 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
* document id to support showing just the chunk that contained the
|
||||
* hit.
|
||||
*/
|
||||
if (hit.getContent() instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile) hit.getContent();
|
||||
if (content instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile) content;
|
||||
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()));
|
||||
@ -503,7 +467,7 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
* Create an account artifact.
|
||||
*/
|
||||
try {
|
||||
newArtifact = hit.getContent().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT);
|
||||
newArtifact = content.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT);
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
|
||||
return null;
|
||||
@ -524,9 +488,7 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
|
||||
try {
|
||||
newArtifact.addAttributes(attributes);
|
||||
KeywordCachedArtifact writeResult = new KeywordCachedArtifact(newArtifact);
|
||||
writeResult.add(attributes);
|
||||
return writeResult;
|
||||
return newArtifact;
|
||||
} catch (TskCoreException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
|
||||
return null;
|
||||
@ -554,7 +516,7 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
* 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
|
||||
* @param attributeMap A map of artifact attribute objects, used to avoid
|
||||
* creating duplicate attributes.
|
||||
* @param matcher A matcher for the snippet.
|
||||
*/
|
||||
@ -567,12 +529,13 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
* 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
|
||||
* @param attributeMap 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, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String groupName, Matcher matcher) {
|
||||
BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrType);
|
||||
@ -589,5 +552,4 @@ final class RegexQuery implements KeywordSearchQuery {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,6 @@
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -46,7 +45,6 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.StopWatch;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
/**
|
||||
* Singleton keyword search manager: Launches search threads for each job and
|
||||
@ -482,9 +480,7 @@ public final class SearchRunner {
|
||||
if (!newResults.getKeywords().isEmpty()) {
|
||||
|
||||
// Write results to BB
|
||||
//new artifacts created, to report to listeners
|
||||
Collection<BlackboardArtifact> newArtifacts = new ArrayList<>();
|
||||
|
||||
|
||||
//scale progress bar more more granular, per result sub-progress, within per keyword
|
||||
int totalUnits = newResults.getKeywords().size();
|
||||
subProgresses[keywordsSearched].start(totalUnits);
|
||||
@ -496,7 +492,7 @@ public final class SearchRunner {
|
||||
subProgresses[keywordsSearched].progress(keywordList.getName() + ": " + queryDisplayStr, unitProgress);
|
||||
|
||||
// Create blackboard artifacts
|
||||
newArtifacts = newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages());
|
||||
newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages());
|
||||
|
||||
} //if has results
|
||||
|
||||
|
@ -824,7 +824,7 @@ public class Server {
|
||||
|
||||
return new Core(coreName, theCase.getCaseType(), index);
|
||||
|
||||
} catch (SolrServerException | SolrException | IOException ex) {
|
||||
} catch (Exception ex) {
|
||||
throw new KeywordSearchModuleException(NbBundle.getMessage(this.getClass(), "Server.openCore.exception.cantOpen.msg"), ex);
|
||||
}
|
||||
}
|
||||
@ -1231,6 +1231,8 @@ public class Server {
|
||||
// the server to access a core needs to be built from a URL with the
|
||||
// core in it, and is only good for core-specific operations
|
||||
private final HttpSolrServer solrCore;
|
||||
|
||||
private final int QUERY_TIMEOUT_MILLISECONDS = 86400000; // 24 Hours = 86,400,000 Milliseconds
|
||||
|
||||
private Core(String name, CaseType caseType, Index index) {
|
||||
this.name = name;
|
||||
@ -1240,7 +1242,8 @@ public class Server {
|
||||
this.solrCore = new HttpSolrServer(currentSolrServer.getBaseURL() + "/" + name); //NON-NLS
|
||||
|
||||
//TODO test these settings
|
||||
//solrCore.setSoTimeout(1000 * 60); // socket read timeout, make large enough so can index larger files
|
||||
// socket read timeout, make large enough so can index larger files
|
||||
solrCore.setSoTimeout(QUERY_TIMEOUT_MILLISECONDS);
|
||||
//solrCore.setConnectionTimeout(1000);
|
||||
solrCore.setDefaultMaxConnectionsPerHost(2);
|
||||
solrCore.setMaxTotalConnections(5);
|
||||
|
@ -42,6 +42,7 @@ 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.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
@ -96,7 +97,7 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
||||
+ "(?:\\?" // end sentinal: ? //NON-NLS
|
||||
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
|
||||
+ "?)?)?)?)?)?");//close nested optional groups //NON-NLS
|
||||
static final Pattern CREDIT_CARD_TRACK2_PATTERN = Pattern.compile(
|
||||
static final Pattern CREDIT_CARD_TRACK2_PATTERN = Pattern.compile(
|
||||
/*
|
||||
* Track 2 is numeric plus six punctuation symbolls :;<=>?
|
||||
*
|
||||
@ -115,7 +116,7 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
||||
+ "(?:[:;<=>?]" //end sentinel //NON-NLS
|
||||
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
|
||||
+ "?)?)?)?)?)?"); //close nested optional groups //NON-NLS
|
||||
static final BlackboardAttribute.Type KEYWORD_SEARCH_DOCUMENT_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID);
|
||||
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
|
||||
@ -315,27 +316,12 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
||||
}
|
||||
results.addResult(new Keyword(term.getTerm(), false, true, originalKeyword.getListName(), originalKeyword.getOriginalTerm()), new ArrayList<>(termHits));
|
||||
}
|
||||
return results;
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the keyword hits for a given search term into artifacts.
|
||||
*
|
||||
* @param foundKeyword The keyword that was found by the search.
|
||||
* @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(Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
|
||||
public BlackboardArtifact writeSingleFileHitsToBlackBoard(Content content, Keyword foundKeyword, 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
|
||||
@ -347,9 +333,9 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
||||
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
|
||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
|
||||
|
||||
|
||||
try {
|
||||
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
|
||||
@ -375,7 +361,7 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
||||
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
|
||||
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.getContentID())); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -411,8 +397,8 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
||||
* document id to support showing just the chunk that contained the
|
||||
* hit.
|
||||
*/
|
||||
if (hit.getContent() instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile) hit.getContent();
|
||||
if (content instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile)content;
|
||||
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()));
|
||||
@ -423,7 +409,7 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
||||
* Create an account artifact.
|
||||
*/
|
||||
try {
|
||||
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
|
||||
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
|
||||
return null;
|
||||
@ -442,12 +428,10 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
||||
|
||||
// TermsComponentQuery is now being used exclusively for substring searches.
|
||||
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.SUBSTRING.ordinal()));
|
||||
|
||||
|
||||
try {
|
||||
newArtifact.addAttributes(attributes);
|
||||
KeywordCachedArtifact writeResult = new KeywordCachedArtifact(newArtifact);
|
||||
writeResult.add(attributes);
|
||||
return writeResult;
|
||||
return newArtifact;
|
||||
} catch (TskCoreException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
|
||||
return null;
|
||||
|
@ -94,6 +94,7 @@ public class AutopsyTestCases {
|
||||
|
||||
public void testNewCaseWizardOpen(String title) {
|
||||
logger.info("New Case");
|
||||
resetTimeouts("WindowWaiter.WaitWindowTimeout", 240000);
|
||||
NbDialogOperator nbdo = new NbDialogOperator(title);
|
||||
JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button
|
||||
jbo.pushNoBlock();
|
||||
@ -121,8 +122,8 @@ public class AutopsyTestCases {
|
||||
*/
|
||||
new Timeout("pausing", 120000).sleep();
|
||||
logger.info("Starting Add Image process");
|
||||
resetTimeouts("WindowWaiter.WaitWindowTimeOut", 240000);
|
||||
WizardOperator wo = new WizardOperator("Add Data Source");
|
||||
wo.setTimeouts(resetTimeouts("WindowWaiter.WaitWindowTimeOut", 240000));
|
||||
while(!wo.btNext().isEnabled()){
|
||||
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
|
||||
}
|
||||
@ -299,6 +300,7 @@ public class AutopsyTestCases {
|
||||
|
||||
public void testGenerateReportButton() throws IOException {
|
||||
logger.info("Generate Report Button");
|
||||
resetTimeouts("ComponentOperator.WaitComponentTimeout", 240000);
|
||||
JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false);
|
||||
JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog);
|
||||
JListOperator listOperator = new JListOperator(reportDialogOperator);
|
||||
@ -307,12 +309,10 @@ public class AutopsyTestCases {
|
||||
Date date = new Date();
|
||||
String datenotime = dateFormat.format(date);
|
||||
listOperator.clickOnItem(0, 1);
|
||||
new Timeout("pausing", 2000).sleep();
|
||||
jbo0.pushNoBlock();
|
||||
new Timeout("pausing", 2000).sleep();
|
||||
JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish");
|
||||
jbo1.pushNoBlock();
|
||||
new Timeout("pausing", 1000).sleep();
|
||||
JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false);
|
||||
screenshot("Progress");
|
||||
JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog);
|
||||
|
@ -0,0 +1,11 @@
|
||||
#Updated by build script
|
||||
#Thu, 22 Jun 2017 08:50:21 -0400
|
||||
LBL_splash_window_title=Starting Autopsy
|
||||
SPLASH_HEIGHT=314
|
||||
SPLASH_WIDTH=538
|
||||
SplashProgressBarBounds=0,308,538,6
|
||||
SplashRunningTextBounds=0,289,538,18
|
||||
SplashRunningTextColor=0x0
|
||||
SplashRunningTextFontSize=19
|
||||
|
||||
currentVersion=Autopsy 4.4.1
|
@ -0,0 +1,4 @@
|
||||
#Updated by build script
|
||||
#Thu, 22 Jun 2017 08:50:21 -0400
|
||||
CTL_MainWindow_Title=Autopsy 4.4.1
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 4.4.1
|
@ -170,7 +170,7 @@
|
||||
<!-- Update configuration file to include jre -->
|
||||
<property name="inst.property.file" value="${inst-path}/etc/${app.name}.conf" />
|
||||
<!-- Sets max heap size to be ${jvm.max.mem} which is set in the run-ai-(32/64) target -->
|
||||
<var name="jvm.args" value=""--branding ${app.name} -J-Xms24m -J-Xmx${jvm.max.mem}m -J-XX:MaxPermSize=128M -J-Xverify:none "" />
|
||||
<var name="jvm.args" value=""--branding ${app.name} -J-Xms24m -J-Xmx${jvm.max.mem}m -J-XX:MaxPermSize=128M -J-Xverify:none -J-XX:+UseG1GC -J-XX:+UseStringDeduplication "" />
|
||||
<propertyfile file="${inst.property.file}">
|
||||
<!-- Note: can be higher on 64 bit systems, should be in sync with project.properties -->
|
||||
<entry key="default_options" value="@JVM_OPTIONS" />
|
||||
|
@ -92,7 +92,7 @@
|
||||
|
||||
<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=""--branding ${app.name} -J-Xms24m -J-XX:MaxPermSize=128M -J-Xverify:none -J-Xdock:name=${app.title}"" />
|
||||
<property name="jvm.options" value=""--branding ${app.name} -J-Xms24m -J-XX:MaxPermSize=128M -J-Xverify:none -J-XX:+UseG1GC -J-XX:+UseStringDeduplication -J-Xdock:name=${app.title}"" />
|
||||
<propertyfile file="${app.property.file}">
|
||||
<!-- Note: can be higher on 64 bit systems, should be in sync with project.properties -->
|
||||
<entry key="default_options" value="@JVM_OPTIONS" />
|
||||
|
@ -4,7 +4,7 @@ app.title=Autopsy
|
||||
### lowercase version of above
|
||||
app.name=${branding.token}
|
||||
### if left unset, version will default to today's date
|
||||
app.version=4.4.1
|
||||
app.version=4.4.2
|
||||
### build.type must be one of: DEVELOPMENT, RELEASE
|
||||
#build.type=RELEASE
|
||||
build.type=DEVELOPMENT
|
||||
@ -16,7 +16,7 @@ update_versions=false
|
||||
#custom JVM options
|
||||
#Note: can be higher on 64 bit systems, should be in sync with build.xml
|
||||
# for Japanese version add: -J-Duser.language=ja
|
||||
run.args.extra=-J-Xms24m -J-XX:MaxPermSize=128M -J-Xverify:none
|
||||
run.args.extra=-J-Xms24m -J-XX:MaxPermSize=128M -J-Xverify:none -J-XX:+UseG1GC -J-XX:+UseStringDeduplication
|
||||
auxiliary.org-netbeans-modules-apisupport-installer.license-type=apache.v2
|
||||
auxiliary.org-netbeans-modules-apisupport-installer.os-linux=false
|
||||
auxiliary.org-netbeans-modules-apisupport-installer.os-macosx=false
|
||||
|
13
ruleset.xml
Normal file
13
ruleset.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="Custom ruleset"
|
||||
xmlns="http://pmd.sf.net/ruleset/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
|
||||
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
|
||||
<description>
|
||||
Ruleset used by Autopsy
|
||||
</description>
|
||||
|
||||
<rule ref="rulesets/java/unusedcode.xml"/>
|
||||
|
||||
</ruleset>
|
@ -17,7 +17,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from tskdbdiff import TskDbDiff, TskDbDiffException
|
||||
from tskdbdiff import TskDbDiff, TskDbDiffException, PGSettings
|
||||
import codecs
|
||||
import datetime
|
||||
import logging
|
||||
@ -132,17 +132,9 @@ class TestRunner(object):
|
||||
"""
|
||||
|
||||
if isMultiUser:
|
||||
if test_config.output_parent_dir.endswith("single_user"):
|
||||
test_config.output_parent_dir = test_config.output_parent_dir.replace("single_user", "multi_user")
|
||||
else:
|
||||
test_config.output_parent_dir += "\\multi_user"
|
||||
test_config.userCaseType='multi'
|
||||
test_config.testUserCase='multi'
|
||||
else:
|
||||
if test_config.output_parent_dir.endswith("multi_user"):
|
||||
test_config.output_parent_dir = test_config.output_parent_dir.replace("multi_user", "single_user")
|
||||
else:
|
||||
test_config.output_parent_dir += "\\single_user"
|
||||
test_config.userCaseType='single'
|
||||
test_config.testUserCase='single'
|
||||
|
||||
test_config._init_logs()
|
||||
|
||||
@ -191,7 +183,7 @@ class TestRunner(object):
|
||||
Errors.print_error("No image had any gold; Regression did not run")
|
||||
exit(1)
|
||||
|
||||
if not all([ test_data.overall_passed for test_data in test_data_list ]):
|
||||
if not (test_config.args.rebuild or all([ test_data.overall_passed for test_data in test_data_list ])):
|
||||
html = open(test_config.html_log)
|
||||
Errors.add_errors_out(html.name)
|
||||
html.close()
|
||||
@ -224,16 +216,17 @@ class TestRunner(object):
|
||||
if ant_line.startswith("BUILD FAILED") or "fatal error" in ant_ignoreCase or "crashed" in ant_ignoreCase:
|
||||
Errors.print_error("Autopsy test failed. Please check the build log antlog.txt for details.")
|
||||
sys.exit(1)
|
||||
# exit if .db was not created
|
||||
if not file_exists(test_data.get_db_path(DBType.OUTPUT)):
|
||||
# exit if a single-user case and the local .db file was not created
|
||||
if not file_exists(test_data.get_db_path(DBType.OUTPUT)) and not test_data.isMultiUser:
|
||||
Errors.print_error("Autopsy did not run properly; No .db file was created")
|
||||
sys.exit(1)
|
||||
try:
|
||||
# Dump the database before we diff or use it for rebuild
|
||||
TskDbDiff.dump_output_db(test_data.get_db_path(DBType.OUTPUT), test_data.get_db_dump_path(DBType.OUTPUT),
|
||||
test_data.get_sorted_data_path(DBType.OUTPUT))
|
||||
db_file = test_data.get_db_path(DBType.OUTPUT)
|
||||
TskDbDiff.dump_output_db(db_file, test_data.get_db_dump_path(DBType.OUTPUT),
|
||||
test_data.get_sorted_data_path(DBType.OUTPUT), test_data.isMultiUser, test_data.pgSettings)
|
||||
except sqlite3.OperationalError as e:
|
||||
Errors.print_error("Ingest did not run properly.\nMake sure no other instances of Autopsy are open and try again.")
|
||||
Errors.print_error("Ingest did not run properly.\nMake sure no other instances of Autopsy are open and try again." + str(e))
|
||||
sys.exit(1)
|
||||
|
||||
# merges logs into a single log for later diff / rebuild
|
||||
@ -374,7 +367,8 @@ class TestRunner(object):
|
||||
|
||||
# Copy files to gold
|
||||
try:
|
||||
shutil.copy(dbinpth, dboutpth)
|
||||
if not test_data.isMultiUser: # This find the local .db file and copy it for single-user case. Multi-user case doesn't have a local db file.
|
||||
shutil.copy(dbinpth, dboutpth)
|
||||
if file_exists(test_data.get_sorted_data_path(DBType.OUTPUT)):
|
||||
shutil.copy(test_data.get_sorted_data_path(DBType.OUTPUT), dataoutpth)
|
||||
shutil.copy(dbdumpinpth, dbdumpoutpth)
|
||||
@ -444,7 +438,7 @@ class TestRunner(object):
|
||||
test_data.ant.append("-Dkeyword_path=" + test_config.keyword_path)
|
||||
test_data.ant.append("-Dnsrl_path=" + test_config.nsrl_path)
|
||||
test_data.ant.append("-Dgold_path=" + test_config.gold)
|
||||
if re.match('^[\w]:', test_data.output_path) == None or test_data.output_path.startswith('/'):
|
||||
if (re.match('^[\w]:', test_data.output_path) == None and not test_data.output_path.startswith("\\\\")) or test_data.output_path.startswith('/'):
|
||||
test_data.ant.append("-Dout_path=" + make_local_path(test_data.output_path))
|
||||
else:
|
||||
test_data.ant.append("-Dout_path=" + test_data.output_path)
|
||||
@ -459,7 +453,7 @@ class TestRunner(object):
|
||||
test_data.ant.append("-DsolrPort=" + str(test_config.solrPort))
|
||||
test_data.ant.append("-DmessageServiceHost=" + test_config.messageServiceHost)
|
||||
test_data.ant.append("-DmessageServicePort=" + str(test_config.messageServicePort))
|
||||
if test_config.userCaseType == "multi":
|
||||
if test_data.isMultiUser:
|
||||
test_data.ant.append("-DisMultiUser=true")
|
||||
# Note: test_data has autopys_version attribute, but we couldn't see it from here. It's set after run ingest.
|
||||
autopsyVersionPath = os.path.join("..", "..", "nbproject", "project.properties")
|
||||
@ -478,7 +472,7 @@ class TestRunner(object):
|
||||
Errors.print_out("Ingesting Image:\n" + test_data.image_file + "\n")
|
||||
Errors.print_out("CMD: " + " ".join(test_data.ant))
|
||||
Errors.print_out("Starting test...\n")
|
||||
if re.match('^[\w]:', test_data.main_config.output_dir) == None or test_data.main_config.output_dir.startswith('/'):
|
||||
if (re.match('^[\w]:', test_data.main_config.output_dir) == None and not test_data.main_config.output_dir.startswith("\\\\")) or test_data.main_config.output_dir.startswith('/'):
|
||||
antoutpth = make_local_path(test_data.main_config.output_dir, "antRunOutput.txt")
|
||||
else:
|
||||
antoutpth = test_data.main_config.output_dir + "\\antRunOutput.txt"
|
||||
@ -572,6 +566,8 @@ class TestData(object):
|
||||
self.image_file = str(image)
|
||||
self.image = get_image_name(self.image_file)
|
||||
self.image_name = self.image
|
||||
# userCaseType
|
||||
self.isMultiUser = True if self.main_config.testUserCase == "multi" else False
|
||||
# Directory structure and files
|
||||
self.output_path = make_path(self.main_config.output_dir, self.image_name)
|
||||
self.autopsy_data_file = make_path(self.output_path, self.image_name + "Autopsy_data.txt")
|
||||
@ -580,13 +576,16 @@ class TestData(object):
|
||||
self.test_dbdump = make_path(self.output_path, self.image_name +
|
||||
"-DBDump.txt")
|
||||
self.common_log_path = make_path(self.output_path, self.image_name + "-Exceptions.txt")
|
||||
self.reports_dir = make_path(self.output_path, AUTOPSY_TEST_CASE, "Reports")
|
||||
if self.isMultiUser:
|
||||
self.reports_dir = make_path(self.output_path, AUTOPSY_TEST_CASE, socket.gethostname(), "Reports")
|
||||
self.solr_index = make_path(self.output_path, AUTOPSY_TEST_CASE, socket.gethostname(), "ModuleOutput", "KeywordSearch")
|
||||
else:
|
||||
self.reports_dir = make_path(self.output_path, AUTOPSY_TEST_CASE, "Reports")
|
||||
self.solr_index = make_path(self.output_path, AUTOPSY_TEST_CASE, "ModuleOutput", "KeywordSearch")
|
||||
self.gold_data_dir = make_path(self.main_config.gold, self.image_name)
|
||||
self.gold_archive = make_path(self.main_config.gold,
|
||||
self.image_name + "-archive.zip")
|
||||
self.logs_dir = make_path(self.output_path, "logs")
|
||||
self.solr_index = make_path(self.output_path, AUTOPSY_TEST_CASE,
|
||||
"ModuleOutput", "KeywordSearch")
|
||||
# Results and Info
|
||||
self.html_report_passed = False
|
||||
self.errors_diff_passed = False
|
||||
@ -611,6 +610,8 @@ class TestData(object):
|
||||
self.printout = []
|
||||
# autopsyPlatform
|
||||
self.autopsyPlatform = str(self.main_config.autopsyPlatform)
|
||||
# postgreSQL db connection data settings
|
||||
self.pgSettings = PGSettings(self.main_config.dbHost, self.main_config.dbPort, self.main_config.dbUserName, self.main_config.dbPassword)
|
||||
|
||||
def ant_to_string(self):
|
||||
string = ""
|
||||
@ -627,7 +628,12 @@ class TestData(object):
|
||||
if(db_type == DBType.GOLD):
|
||||
db_path = make_path(self.gold_data_dir, DB_FILENAME)
|
||||
elif(db_type == DBType.OUTPUT):
|
||||
db_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, DB_FILENAME)
|
||||
if self.isMultiUser:
|
||||
case_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, "AutopsyTestCase.aut")
|
||||
parsed = parse(case_path)
|
||||
db_path = parsed.getElementsByTagName("CaseDatabase")[0].firstChild.data
|
||||
else:
|
||||
db_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, DB_FILENAME)
|
||||
else:
|
||||
db_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, BACKUP_DB_FILENAME)
|
||||
return db_path
|
||||
@ -735,9 +741,11 @@ class TestConfiguration(object):
|
||||
self.args = args
|
||||
# Default output parent dir
|
||||
self.output_parent_dir = make_path("..", "output", "results")
|
||||
self.output_dir = ""
|
||||
self.output_dir = ""
|
||||
self.singleUser_outdir = ""
|
||||
self.input_dir = make_local_path("..","input")
|
||||
self.gold = make_path("..", "output", "gold")
|
||||
self.gold = ""
|
||||
self.singleUser_gold = make_path("..", "output", "gold", "single_user")
|
||||
# Logs:
|
||||
self.csv = ""
|
||||
self.global_csv = ""
|
||||
@ -769,7 +777,11 @@ class TestConfiguration(object):
|
||||
self.messageServiceHost = ""
|
||||
self.messageServicePort = ""
|
||||
self.userCaseType = "Both"
|
||||
self.multiUser_gold = make_path("..", "output", "gold", "multi_user")
|
||||
self.multiUser_outdir = ""
|
||||
|
||||
# Test runner user case:
|
||||
self.testUserCase = ""
|
||||
if not self.args.single:
|
||||
self._load_config_file(self.args.config_file)
|
||||
else:
|
||||
@ -789,21 +801,21 @@ class TestConfiguration(object):
|
||||
parsed_config = parse(config_file)
|
||||
logres = []
|
||||
counts = {}
|
||||
if parsed_config.getElementsByTagName("userCaseType"):
|
||||
self.userCaseType = parsed_config.getElementsByTagName("userCaseType")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("indir"):
|
||||
self.input_dir = parsed_config.getElementsByTagName("indir")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("outdir"):
|
||||
self.output_parent_dir = parsed_config.getElementsByTagName("outdir")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("global_csv"):
|
||||
self.global_csv = parsed_config.getElementsByTagName("global_csv")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if re.match('^[\w]:', self.global_csv) == None or self.global_csv.startswith('/'):
|
||||
self.global_csv = make_local_path(self.global_csv)
|
||||
if parsed_config.getElementsByTagName("golddir"):
|
||||
self.gold = parsed_config.getElementsByTagName("golddir")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("singleUser_outdir"):
|
||||
self.singleUser_outdir = parsed_config.getElementsByTagName("singleUser_outdir")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("singleUser_golddir"):
|
||||
self.singleUser_gold = parsed_config.getElementsByTagName("singleUser_golddir")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("timing"):
|
||||
self.timing = parsed_config.getElementsByTagName("timing")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("autopsyPlatform"):
|
||||
self.autopsyPlatform = parsed_config.getElementsByTagName("autopsyPlatform")[0].getAttribute("value").encode().decode("utf_8")
|
||||
# Multi-user settings
|
||||
if parsed_config.getElementsByTagName("multiUser_golddir"):
|
||||
self.multiUser_gold = parsed_config.getElementsByTagName("multiUser_golddir")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("dbHost"):
|
||||
self.dbHost = parsed_config.getElementsByTagName("dbHost")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("dbPort"):
|
||||
@ -820,8 +832,8 @@ class TestConfiguration(object):
|
||||
self.messageServiceHost = parsed_config.getElementsByTagName("messageServiceHost")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("messageServicePort"):
|
||||
self.messageServicePort = parsed_config.getElementsByTagName("messageServicePort")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("userCaseType"):
|
||||
self.userCaseType = parsed_config.getElementsByTagName("userCaseType")[0].getAttribute("value").encode().decode("utf_8")
|
||||
if parsed_config.getElementsByTagName("multiUser_outdir"):
|
||||
self.multiUser_outdir = parsed_config.getElementsByTagName("multiUser_outdir")[0].getAttribute("value").encode().decode("utf_8")
|
||||
self._init_imgs(parsed_config)
|
||||
self._init_build_info(parsed_config)
|
||||
|
||||
@ -831,7 +843,7 @@ class TestConfiguration(object):
|
||||
logging.critical(traceback.format_exc())
|
||||
print(traceback.format_exc())
|
||||
|
||||
if self.userCaseType.lower().startswith("multi"):
|
||||
if self.userCaseType.lower().startswith("multi") or self.userCaseType.lower().startswith("both"):
|
||||
if not self.dbHost.strip() or not self.dbPort.strip() or not self.dbUserName.strip() or not self.dbPassword.strip():
|
||||
Errors.print_error("Please provide database connection information via configuration file. ")
|
||||
sys.exit(1)
|
||||
@ -841,18 +853,31 @@ class TestConfiguration(object):
|
||||
if not self.messageServiceHost.strip() or not self.messageServicePort.strip():
|
||||
Errors.print_error("Please provide ActiveMQ host name and port number via configuration file. ")
|
||||
sys.exit(1)
|
||||
|
||||
if not self.multiUser_outdir.strip():
|
||||
Errors.print_error("Please provide a shared output directory for multi-user test. ")
|
||||
sys.exit(1)
|
||||
|
||||
def _init_logs(self):
|
||||
"""Setup output folder, logs, and reporting infrastructure."""
|
||||
user_case_type = self.userCaseType.lower()
|
||||
if self.testUserCase == "multi":
|
||||
self.output_parent_dir = self.multiUser_outdir
|
||||
self.gold = self.multiUser_gold
|
||||
else:
|
||||
self.output_parent_dir = self.singleUser_outdir
|
||||
self.gold = self.singleUser_gold
|
||||
|
||||
if not dir_exists(self.output_parent_dir):
|
||||
print(_platform)
|
||||
print(self.output_parent_dir)
|
||||
os.makedirs(make_os_path(_platform, self.output_parent_dir))
|
||||
self.global_csv = make_path(os.path.join(self.output_parent_dir, "Global_CSV.log"))
|
||||
self.output_dir = make_path(self.output_parent_dir, time.strftime("%Y.%m.%d-%H.%M.%S"))
|
||||
|
||||
os.makedirs(self.output_dir)
|
||||
self.csv = make_path(self.output_dir, "CSV.txt")
|
||||
self.html_log = make_path(self.output_dir, "AutopsyTestCase.html")
|
||||
log_name = ''
|
||||
if SYS is OS.CYGWIN and (re.match('^[\w]:', self.output_dir) != None or not self.output_dir.startswith('/')):
|
||||
if SYS is OS.CYGWIN and ((re.match('^[\w]:', self.output_dir) != None and self.output_dir.startswith("\\\\")) or not self.output_dir.startswith('/')):
|
||||
a = ["cygpath", "-u", self.output_dir]
|
||||
cygpath_output_dir = subprocess.check_output(a).decode('utf-8')
|
||||
log_name = cygpath_output_dir.rstrip() + "/regression.log"
|
||||
@ -860,6 +885,22 @@ class TestConfiguration(object):
|
||||
log_name = self.output_dir + "\\regression.log"
|
||||
logging.basicConfig(filename=log_name, level=logging.DEBUG)
|
||||
|
||||
# Sanity check to see if there are obvious gold images that we are not testing
|
||||
if not dir_exists(self.gold):
|
||||
print(self.gold)
|
||||
Errors.print_error("Gold folder does not exist")
|
||||
sys.exit(1)
|
||||
gold_count = 0
|
||||
for file in os.listdir(self.gold):
|
||||
if not(file == 'tmp'):
|
||||
gold_count+=1
|
||||
|
||||
image_count = len(self.images)
|
||||
if (image_count > gold_count):
|
||||
print("******Alert: There are more input images than gold standards, some images will not be properly tested.\n")
|
||||
elif (image_count < gold_count):
|
||||
print("******Alert: There are more gold standards than input images, this will not check all gold Standards.\n")
|
||||
|
||||
def _init_build_info(self, parsed_config):
|
||||
"""Initializes paths that point to information necessary to run the AutopsyIngest."""
|
||||
build_elements = parsed_config.getElementsByTagName("build")
|
||||
@ -878,22 +919,6 @@ class TestConfiguration(object):
|
||||
else:
|
||||
msg = "File: " + value + " doesn't exist"
|
||||
Errors.print_error(msg)
|
||||
image_count = len(self.images)
|
||||
|
||||
# Sanity check to see if there are obvious gold images that we are not testing
|
||||
if not dir_exists(self.gold):
|
||||
Errors.print_error("Gold folder does not exist")
|
||||
sys.exit(1)
|
||||
gold_count = 0
|
||||
for file in os.listdir(self.gold):
|
||||
if not(file == 'tmp'):
|
||||
gold_count+=1
|
||||
|
||||
if (image_count > gold_count):
|
||||
print("******Alert: There are more input images than gold standards, some images will not be properly tested.\n")
|
||||
elif (image_count < gold_count):
|
||||
print("******Alert: There are more gold standards than input images, this will not check all gold Standards.\n")
|
||||
|
||||
|
||||
#-------------------------------------------------#
|
||||
# Functions relating to comparing outputs #
|
||||
@ -915,7 +940,7 @@ class TestResultsDiffer(object):
|
||||
gold_bb_dump = test_data.get_sorted_data_path(DBType.GOLD)
|
||||
gold_dump = test_data.get_db_dump_path(DBType.GOLD)
|
||||
test_data.db_diff_passed = all(TskDbDiff(output_db, gold_db, output_dir=output_dir, gold_bb_dump=gold_bb_dump,
|
||||
gold_dump=gold_dump).run_diff())
|
||||
gold_dump=gold_dump, isMultiUser=test_data.isMultiUser, pgSettings=test_data.pgSettings).run_diff())
|
||||
|
||||
# Compare Exceptions
|
||||
# replace is a fucntion that replaces strings of digits with 'd'
|
||||
@ -982,7 +1007,7 @@ class TestResultsDiffer(object):
|
||||
|
||||
# create file path for gold files inside report output folder. In case of diff, both gold and current run
|
||||
# Exception.txt files are available in the report output folder. Prefix Gold- is added to the filename.
|
||||
gold_file_in_output_dir = output_file[:output_file.rfind("\\")] + "Gold-" + output_file[output_file.rfind("\\")+1:]
|
||||
gold_file_in_output_dir = output_file[:output_file.rfind("\\")] + "\\Gold-" + output_file[output_file.rfind("\\")+1:]
|
||||
shutil.copy(gold_file, gold_file_in_output_dir)
|
||||
|
||||
return False
|
||||
@ -1579,7 +1604,10 @@ def copy_logs(test_data):
|
||||
"""
|
||||
try:
|
||||
# copy logs from autopsy case's Log folder
|
||||
log_dir = os.path.join(test_data.output_path, AUTOPSY_TEST_CASE, "Log")
|
||||
if test_data.isMultiUser:
|
||||
log_dir = os.path.join(test_data.output_path, AUTOPSY_TEST_CASE, socket.gethostname(), "Log")
|
||||
else:
|
||||
log_dir = os.path.join(test_data.output_path, AUTOPSY_TEST_CASE, "Log")
|
||||
shutil.copytree(log_dir, test_data.logs_dir)
|
||||
|
||||
# copy logs from userdir0/var/log
|
||||
|
@ -8,6 +8,9 @@ import os
|
||||
import codecs
|
||||
import datetime
|
||||
import sys
|
||||
import psycopg2
|
||||
import psycopg2.extras
|
||||
import socket
|
||||
|
||||
class TskDbDiff(object):
|
||||
"""Compares two TSK/Autospy SQLite databases.
|
||||
@ -27,7 +30,7 @@ class TskDbDiff(object):
|
||||
autopsy_db_file:
|
||||
gold_db_file:
|
||||
"""
|
||||
def __init__(self, output_db, gold_db, output_dir=None, gold_bb_dump=None, gold_dump=None, verbose=False):
|
||||
def __init__(self, output_db, gold_db, output_dir=None, gold_bb_dump=None, gold_dump=None, verbose=False, isMultiUser=False, pgSettings=None):
|
||||
"""Constructor for TskDbDiff.
|
||||
|
||||
Args:
|
||||
@ -51,6 +54,12 @@ class TskDbDiff(object):
|
||||
self._bb_dump = ""
|
||||
self._dump = ""
|
||||
self.verbose = verbose
|
||||
self.isMultiUser = isMultiUser
|
||||
self.pgSettings = pgSettings
|
||||
|
||||
if self.isMultiUser and not self.pgSettings:
|
||||
print("Missing PostgreSQL database connection settings data.")
|
||||
sys.exit(1)
|
||||
|
||||
if self.gold_bb_dump is None:
|
||||
self._generate_gold_bb_dump = True
|
||||
@ -68,13 +77,13 @@ class TskDbDiff(object):
|
||||
|
||||
# generate the gold database dumps if necessary
|
||||
if self._generate_gold_dump:
|
||||
TskDbDiff._dump_output_db_nonbb(self.gold_db_file, self.gold_dump)
|
||||
TskDbDiff._dump_output_db_nonbb(self.gold_db_file, self.gold_dump, self.isMultiUser, self.pgSettings)
|
||||
if self._generate_gold_bb_dump:
|
||||
TskDbDiff._dump_output_db_bb(self.gold_db_file, self.gold_bb_dump)
|
||||
TskDbDiff._dump_output_db_bb(self.gold_db_file, self.gold_bb_dump, self.isMultiUser, self.pgSettings)
|
||||
|
||||
# generate the output database dumps (both DB and BB)
|
||||
TskDbDiff._dump_output_db_nonbb(self.output_db_file, self._dump)
|
||||
TskDbDiff._dump_output_db_bb(self.output_db_file, self._bb_dump)
|
||||
TskDbDiff._dump_output_db_nonbb(self.output_db_file, self._dump, self.isMultiUser, self.pgSettings)
|
||||
TskDbDiff._dump_output_db_bb(self.output_db_file, self._bb_dump, self.isMultiUser, self.pgSettings)
|
||||
|
||||
# Compare non-BB
|
||||
dump_diff_pass = self._diff(self._dump, self.gold_dump, self._dump_diff)
|
||||
@ -163,7 +172,7 @@ class TskDbDiff(object):
|
||||
return False
|
||||
|
||||
|
||||
def _dump_output_db_bb(db_file, bb_dump_file):
|
||||
def _dump_output_db_bb(db_file, bb_dump_file, isMultiUser, pgSettings):
|
||||
"""Dumps sorted text results to the given output location.
|
||||
|
||||
Smart method that deals with a blackboard comparison to avoid issues
|
||||
@ -175,12 +184,14 @@ class TskDbDiff(object):
|
||||
"""
|
||||
|
||||
unsorted_dump = TskDbDiff._get_tmp_file("dump_data", ".txt")
|
||||
conn = sqlite3.connect(db_file)
|
||||
conn.text_factory = lambda x: x.decode("utf-8", "ignore")
|
||||
conn.row_factory = sqlite3.Row
|
||||
|
||||
artifact_cursor = conn.cursor()
|
||||
|
||||
if isMultiUser:
|
||||
conn, unused_db = db_connect(db_file, isMultiUser, pgSettings)
|
||||
artifact_cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
|
||||
else: # Use Sqlite
|
||||
conn = sqlite3.connect(db_file)
|
||||
conn.text_factory = lambda x: x.decode("utf-8", "ignore")
|
||||
conn.row_factory = sqlite3.Row
|
||||
artifact_cursor = conn.cursor()
|
||||
# Get the list of all artifacts (along with type and associated file)
|
||||
# @@@ Could add a SORT by parent_path in here since that is how we are going to later sort it.
|
||||
artifact_cursor.execute("SELECT tsk_files.parent_path, tsk_files.name, blackboard_artifact_types.display_name, blackboard_artifacts.artifact_id FROM blackboard_artifact_types INNER JOIN blackboard_artifacts ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id INNER JOIN tsk_files ON tsk_files.obj_id = blackboard_artifacts.obj_id")
|
||||
@ -201,14 +212,22 @@ class TskDbDiff(object):
|
||||
else:
|
||||
database_log.write(row["name"] + ' <artifact type="' + row["display_name"] + '" > ')
|
||||
|
||||
# Get attributes for this artifact
|
||||
attribute_cursor = conn.cursor()
|
||||
if isMultiUser:
|
||||
attribute_cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
|
||||
else:
|
||||
attribute_cursor = conn.cursor()
|
||||
looptry = True
|
||||
artifact_count += 1
|
||||
try:
|
||||
art_id = ""
|
||||
art_id = str(row["artifact_id"])
|
||||
attribute_cursor.execute("SELECT blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double FROM blackboard_attributes INNER JOIN blackboard_attribute_types ON blackboard_attributes.attribute_type_id = blackboard_attribute_types.attribute_type_id WHERE artifact_id =? ORDER BY blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double", [art_id])
|
||||
|
||||
# Get attributes for this artifact
|
||||
if isMultiUser:
|
||||
attribute_cursor.execute("SELECT blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double FROM blackboard_attributes INNER JOIN blackboard_attribute_types ON blackboard_attributes.attribute_type_id = blackboard_attribute_types.attribute_type_id WHERE artifact_id = %s ORDER BY blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double", [art_id])
|
||||
else:
|
||||
attribute_cursor.execute("SELECT blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double FROM blackboard_attributes INNER JOIN blackboard_attribute_types ON blackboard_attributes.attribute_type_id = blackboard_attribute_types.attribute_type_id WHERE artifact_id =? ORDER BY blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double", [art_id])
|
||||
|
||||
attributes = attribute_cursor.fetchall()
|
||||
|
||||
# Print attributes
|
||||
@ -238,13 +257,13 @@ class TskDbDiff(object):
|
||||
elif attr["value_type"] == 2:
|
||||
attr_value_as_string = str(attr["value_int64"])
|
||||
elif attr["value_type"] == 3:
|
||||
attr_value_as_string = str(attr["value_double"])
|
||||
attr_value_as_string = "%20.10f" % float((attr["value_double"])) #use exact format from db schema to avoid python auto format double value to (0E-10) scientific style
|
||||
elif attr["value_type"] == 4:
|
||||
attr_value_as_string = "bytes"
|
||||
elif attr["value_type"] == 5:
|
||||
attr_value_as_string = str(attr["value_int64"])
|
||||
if attr["display_name"] == "Associated Artifact":
|
||||
attr_value_as_string = getAssociatedArtifactType(db_file, attr_value_as_string)
|
||||
attr_value_as_string = getAssociatedArtifactType(attribute_cursor, attr_value_as_string, isMultiUser)
|
||||
patrn = re.compile("[\n\0\a\b\r\f]")
|
||||
attr_value_as_string = re.sub(patrn, ' ', attr_value_as_string)
|
||||
database_log.write('<attribute source="' + attr["source"] + '" type="' + attr["display_name"] + '" value="' + attr_value_as_string + '" />')
|
||||
@ -283,7 +302,7 @@ class TskDbDiff(object):
|
||||
subprocess.call(srtcmdlst)
|
||||
|
||||
|
||||
def _dump_output_db_nonbb(db_file, dump_file):
|
||||
def _dump_output_db_nonbb(db_file, dump_file, isMultiUser, pgSettings):
|
||||
"""Dumps a database to a text file.
|
||||
|
||||
Does not dump the artifact and attributes.
|
||||
@ -293,43 +312,59 @@ class TskDbDiff(object):
|
||||
dump_file: a pathto_File, the location to dump the non-blackboard database items
|
||||
"""
|
||||
|
||||
# Make a copy that we can modify
|
||||
backup_db_file = TskDbDiff._get_tmp_file("tsk_backup_db", ".db")
|
||||
shutil.copy(db_file, backup_db_file)
|
||||
# We sometimes get situations with messed up permissions
|
||||
os.chmod (backup_db_file, 0o777)
|
||||
|
||||
conn = sqlite3.connect(backup_db_file)
|
||||
id_files_table = build_id_files_table(conn.cursor())
|
||||
id_vs_parts_table = build_id_vs_parts_table(conn.cursor())
|
||||
id_vs_info_table = build_id_vs_info_table(conn.cursor())
|
||||
id_fs_info_table = build_id_fs_info_table(conn.cursor())
|
||||
id_objects_table = build_id_objects_table(conn.cursor())
|
||||
id_artifact_types_table = build_id_artifact_types_table(conn.cursor())
|
||||
conn, backup_db_file = db_connect(db_file, isMultiUser, pgSettings)
|
||||
id_files_table = build_id_files_table(conn.cursor(), isMultiUser)
|
||||
id_vs_parts_table = build_id_vs_parts_table(conn.cursor(), isMultiUser)
|
||||
id_vs_info_table = build_id_vs_info_table(conn.cursor(), isMultiUser)
|
||||
id_fs_info_table = build_id_fs_info_table(conn.cursor(), isMultiUser)
|
||||
id_objects_table = build_id_objects_table(conn.cursor(), isMultiUser)
|
||||
id_artifact_types_table = build_id_artifact_types_table(conn.cursor(), isMultiUser)
|
||||
id_obj_path_table = build_id_obj_path_table(id_files_table, id_objects_table, id_artifact_types_table)
|
||||
|
||||
conn.text_factory = lambda x: x.decode("utf-8", "ignore")
|
||||
|
||||
# Delete the blackboard tables
|
||||
conn.execute("DROP TABLE blackboard_artifacts")
|
||||
conn.execute("DROP TABLE blackboard_attributes")
|
||||
|
||||
# Write to the database dump
|
||||
with codecs.open(dump_file, "wb", "utf_8") as db_log:
|
||||
for line in conn.iterdump():
|
||||
line = normalize_db_entry(line, id_obj_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_table)
|
||||
db_log.write('%s\n' % line)
|
||||
# Now sort the file
|
||||
|
||||
#line = normalize_db_entry(line, id_obj_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_table)
|
||||
if isMultiUser: # Use PostgreSQL
|
||||
os.environ['PGPASSWORD']=pgSettings.password
|
||||
pgDump = ["pg_dump", "--inserts", "-U", pgSettings.username, "-h", pgSettings.pgHost, "-p", pgSettings.pgPort, "-d", db_file, "-E", "utf-8", "-T", "blackboard_artifacts", "-T", "blackboard_attributes", "-f", "postgreSQLDump.sql"]
|
||||
subprocess.call(pgDump)
|
||||
postgreSQL_db = codecs.open("postgreSQLDump.sql", "r", "utf-8")
|
||||
# Write to the database dump
|
||||
with codecs.open(dump_file, "wb", "utf_8") as db_log:
|
||||
dump_line = ''
|
||||
for line in postgreSQL_db:
|
||||
line = line.strip('\r\n ')
|
||||
# Deal with pg_dump result file
|
||||
if line.startswith('--') or line.lower().startswith('alter') or not line: # It's comment or alter statement or empty line
|
||||
continue
|
||||
elif not line.endswith(';'): # Statement not finished
|
||||
dump_line += line
|
||||
continue
|
||||
else:
|
||||
dump_line += line
|
||||
dump_line = normalize_db_entry(dump_line, id_obj_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_table)
|
||||
db_log.write('%s\n' % dump_line)
|
||||
dump_line = ''
|
||||
postgreSQL_db.close()
|
||||
else: # use Sqlite
|
||||
# Delete the blackboard tables
|
||||
conn.text_factory = lambda x: x.decode("utf-8", "ignore")
|
||||
conn.execute("DROP TABLE blackboard_artifacts")
|
||||
conn.execute("DROP TABLE blackboard_attributes")
|
||||
# Write to the database dump
|
||||
with codecs.open(dump_file, "wb", "utf_8") as db_log:
|
||||
for line in conn.iterdump():
|
||||
line = normalize_db_entry(line, id_obj_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_table)
|
||||
db_log.write('%s\n' % line)
|
||||
# Now sort the file
|
||||
srtcmdlst = ["sort", dump_file, "-o", dump_file]
|
||||
subprocess.call(srtcmdlst)
|
||||
|
||||
conn.close()
|
||||
# cleanup the backup
|
||||
os.remove(backup_db_file)
|
||||
if backup_db_file:
|
||||
os.remove(backup_db_file)
|
||||
|
||||
|
||||
def dump_output_db(db_file, dump_file, bb_dump_file):
|
||||
def dump_output_db(db_file, dump_file, bb_dump_file, isMultiUser, pgSettings):
|
||||
"""Dumps the given database to text files for later comparison.
|
||||
|
||||
Args:
|
||||
@ -337,8 +372,8 @@ class TskDbDiff(object):
|
||||
dump_file: a pathto_File, the location to dump the non-blackboard database items
|
||||
bb_dump_file: a pathto_File, the location to dump the blackboard database items
|
||||
"""
|
||||
TskDbDiff._dump_output_db_nonbb(db_file, dump_file)
|
||||
TskDbDiff._dump_output_db_bb(db_file, bb_dump_file)
|
||||
TskDbDiff._dump_output_db_nonbb(db_file, dump_file, isMultiUser, pgSettings)
|
||||
TskDbDiff._dump_output_db_bb(db_file, bb_dump_file, isMultiUser, pgSettings)
|
||||
|
||||
|
||||
def _get_tmp_file(base, ext):
|
||||
@ -349,6 +384,26 @@ class TskDbDiff(object):
|
||||
class TskDbDiffException(Exception):
|
||||
pass
|
||||
|
||||
class PGSettings(object):
|
||||
def __init__(self, pgHost=None, pgPort=5432, user=None, password=None):
|
||||
self.pgHost = pgHost
|
||||
self.pgPort = pgPort
|
||||
self.username = user
|
||||
self.password = password
|
||||
|
||||
def get_pgHost():
|
||||
return self.pgHost
|
||||
|
||||
def get_pgPort():
|
||||
return self.pgPort
|
||||
|
||||
def get_username():
|
||||
return self.username
|
||||
|
||||
def get_password():
|
||||
return self.password
|
||||
|
||||
|
||||
def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info_table, objects_table):
|
||||
""" Make testing more consistent and reasonable by doctoring certain db entries.
|
||||
|
||||
@ -357,25 +412,23 @@ def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info
|
||||
files_table: a map from object ids to file paths.
|
||||
"""
|
||||
|
||||
files_index = line.find('INSERT INTO "tsk_files"')
|
||||
path_index = line.find('INSERT INTO "tsk_files_path"')
|
||||
object_index = line.find('INSERT INTO "tsk_objects"')
|
||||
report_index = line.find('INSERT INTO "reports"')
|
||||
layout_index = line.find('INSERT INTO "tsk_file_layout"')
|
||||
data_source_info_index = line.find('INSERT INTO "data_source_info"')
|
||||
ingest_job_index = line.find('INSERT INTO "ingest_jobs"')
|
||||
|
||||
# Sqlite statement use double quotes for table name, PostgreSQL doesn't. We check both databases results for normalization.
|
||||
files_index = line.find('INSERT INTO "tsk_files"') > -1 or line.find('INSERT INTO tsk_files ') > -1
|
||||
path_index = line.find('INSERT INTO "tsk_files_path"') > -1 or line.find('INSERT INTO tsk_files_path ') > -1
|
||||
object_index = line.find('INSERT INTO "tsk_objects"') > -1 or line.find('INSERT INTO tsk_objects ') > -1
|
||||
report_index = line.find('INSERT INTO "reports"') > -1 or line.find('INSERT INTO reports ') > -1
|
||||
layout_index = line.find('INSERT INTO "tsk_file_layout"') > -1 or line.find('INSERT INTO tsk_file_layout ') > -1
|
||||
data_source_info_index = line.find('INSERT INTO "data_source_info"') > -1 or line.find('INSERT INTO data_source_info ') > -1
|
||||
ingest_job_index = line.find('INSERT INTO "ingest_jobs"') > -1 or line.find('INSERT INTO ingest_jobs ') > -1
|
||||
parens = line[line.find('(') + 1 : line.rfind(')')]
|
||||
fields_list = parens.replace(" ", "").split(',')
|
||||
|
||||
# remove object ID
|
||||
if (files_index != -1):
|
||||
obj_id = fields_list[0]
|
||||
path = files_table[int(obj_id)]
|
||||
if files_index:
|
||||
newLine = ('INSERT INTO "tsk_files" VALUES(' + ', '.join(fields_list[1:]) + ');')
|
||||
return newLine
|
||||
# remove object ID
|
||||
elif (path_index != -1):
|
||||
elif path_index:
|
||||
obj_id = int(fields_list[0])
|
||||
objValue = files_table[obj_id]
|
||||
# remove the obj_id from ModuleOutput/EmbeddedFileExtractor directory
|
||||
@ -387,16 +440,21 @@ def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info
|
||||
pathValue = fields_list[1][:idx_pre+1] + dir_to_replace + fields_list[1][idx_pos:]
|
||||
else:
|
||||
pathValue = fields_list[1]
|
||||
# remove localhost from postgres par_obj_name
|
||||
multiOutput_idx = pathValue.find('ModuleOutput')
|
||||
if multiOutput_idx > -1:
|
||||
pathValue = "'" + pathValue[pathValue.find('ModuleOutput'):] #postgres par_obj_name include losthost
|
||||
|
||||
newLine = ('INSERT INTO "tsk_files_path" VALUES(' + objValue + ', ' + pathValue + ', ' + ', '.join(fields_list[2:]) + ');')
|
||||
return newLine
|
||||
# remove object ID
|
||||
elif (layout_index != -1):
|
||||
elif layout_index:
|
||||
obj_id = fields_list[0]
|
||||
path= files_table[int(obj_id)]
|
||||
newLine = ('INSERT INTO "tsk_file_layout" VALUES(' + path + ', ' + ', '.join(fields_list[1:]) + ');')
|
||||
return newLine
|
||||
# remove object ID
|
||||
elif (object_index != -1):
|
||||
elif object_index:
|
||||
obj_id = fields_list[0]
|
||||
parent_id = fields_list[1]
|
||||
newLine = 'INSERT INTO "tsk_objects" VALUES('
|
||||
@ -434,47 +492,38 @@ def normalize_db_entry(line, files_table, vs_parts_table, vs_info_table, fs_info
|
||||
else:
|
||||
return line
|
||||
# remove time-based information, ie Test_6/11/14 -> Test
|
||||
elif (report_index != -1):
|
||||
elif report_index:
|
||||
fields_list[1] = "AutopsyTestCase"
|
||||
fields_list[2] = "0"
|
||||
newLine = ('INSERT INTO "reports" VALUES(' + ','.join(fields_list) + ');')
|
||||
newLine = ('INSERT INTO "reports" VALUES(' + ','.join(fields_list[1:]) + ');') # remove report_id
|
||||
return newLine
|
||||
elif (data_source_info_index != -1):
|
||||
elif data_source_info_index:
|
||||
fields_list[1] = "{device id}"
|
||||
newLine = ('INSERT INTO "data_source_info" VALUES(' + ','.join(fields_list) + ');')
|
||||
return newLine
|
||||
elif (ingest_job_index != -1):
|
||||
elif ingest_job_index:
|
||||
fields_list[2] = "{host_name}"
|
||||
start_time = int(fields_list[3])
|
||||
end_time = int(fields_list[4])
|
||||
if (start_time <= end_time):
|
||||
fields_list[3] = "0"
|
||||
fields_list[4] = "0"
|
||||
newLine = ('INSERT INTO "injest_jobs" VALUES(' + ','.join(fields_list) + ');')
|
||||
newLine = ('INSERT INTO "ingest_jobs" VALUES(' + ','.join(fields_list) + ');')
|
||||
return newLine
|
||||
else:
|
||||
return line
|
||||
|
||||
def getAssociatedArtifactType(db_file, artifact_id):
|
||||
# Make a copy that we can modify
|
||||
backup_db_file = TskDbDiff._get_tmp_file("tsk_backup_db", ".db")
|
||||
shutil.copy(db_file, backup_db_file)
|
||||
# We sometimes get situations with messed up permissions
|
||||
os.chmod (backup_db_file, 0o777)
|
||||
def getAssociatedArtifactType(cur, artifact_id, isMultiUser):
|
||||
if isMultiUser:
|
||||
cur.execute("SELECT tsk_files.parent_path, blackboard_artifact_types.display_name FROM blackboard_artifact_types INNER JOIN blackboard_artifacts ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id INNER JOIN tsk_files ON tsk_files.obj_id = blackboard_artifacts.obj_id WHERE artifact_id=%s",[artifact_id])
|
||||
else:
|
||||
cur.execute("SELECT tsk_files.parent_path, blackboard_artifact_types.display_name FROM blackboard_artifact_types INNER JOIN blackboard_artifacts ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id INNER JOIN tsk_files ON tsk_files.obj_id = blackboard_artifacts.obj_id WHERE artifact_id=?",[artifact_id])
|
||||
|
||||
conn = sqlite3.connect(backup_db_file)
|
||||
cur = conn.cursor()
|
||||
#artifact_cursor.execute("SELECT display_name FROM blackboard_artifact_types WHERE artifact_id=?",[artifact_id])
|
||||
cur.execute("SELECT tsk_files.parent_path, blackboard_artifact_types.display_name FROM blackboard_artifact_types INNER JOIN blackboard_artifacts ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id INNER JOIN tsk_files ON tsk_files.obj_id = blackboard_artifacts.obj_id WHERE artifact_id=?",[artifact_id])
|
||||
info = cur.fetchone()
|
||||
|
||||
conn.close()
|
||||
# cleanup the backup
|
||||
os.remove(backup_db_file)
|
||||
|
||||
return "File path: " + info[0] + " Artifact Type: " + info[1]
|
||||
|
||||
def build_id_files_table(db_cursor):
|
||||
def build_id_files_table(db_cursor, isPostgreSQL):
|
||||
"""Build the map of object ids to file paths.
|
||||
|
||||
Args:
|
||||
@ -482,10 +531,10 @@ def build_id_files_table(db_cursor):
|
||||
"""
|
||||
# for each row in the db, take the object id, parent path, and name, then create a tuple in the dictionary
|
||||
# with the object id as the key and the full file path (parent + name) as the value
|
||||
mapping = dict([(row[0], str(row[1]) + str(row[2])) for row in db_cursor.execute("SELECT obj_id, parent_path, name FROM tsk_files")])
|
||||
mapping = dict([(row[0], str(row[1]) + str(row[2])) for row in sql_select_execute(db_cursor, isPostgreSQL, "SELECT obj_id, parent_path, name FROM tsk_files")])
|
||||
return mapping
|
||||
|
||||
def build_id_vs_parts_table(db_cursor):
|
||||
def build_id_vs_parts_table(db_cursor, isPostgreSQL):
|
||||
"""Build the map of object ids to vs_parts.
|
||||
|
||||
Args:
|
||||
@ -493,10 +542,10 @@ def build_id_vs_parts_table(db_cursor):
|
||||
"""
|
||||
# for each row in the db, take the object id, addr, and start, then create a tuple in the dictionary
|
||||
# with the object id as the key and (addr + start) as the value
|
||||
mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in db_cursor.execute("SELECT obj_id, addr, start FROM tsk_vs_parts")])
|
||||
mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in sql_select_execute(db_cursor, isPostgreSQL, "SELECT obj_id, addr, start FROM tsk_vs_parts")])
|
||||
return mapping
|
||||
|
||||
def build_id_vs_info_table(db_cursor):
|
||||
def build_id_vs_info_table(db_cursor, isPostgreSQL):
|
||||
"""Build the map of object ids to vs_info.
|
||||
|
||||
Args:
|
||||
@ -504,11 +553,11 @@ def build_id_vs_info_table(db_cursor):
|
||||
"""
|
||||
# for each row in the db, take the object id, vs_type, and img_offset, then create a tuple in the dictionary
|
||||
# with the object id as the key and (vs_type + img_offset) as the value
|
||||
mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in db_cursor.execute("SELECT obj_id, vs_type, img_offset FROM tsk_vs_info")])
|
||||
mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in sql_select_execute(db_cursor, isPostgreSQL, "SELECT obj_id, vs_type, img_offset FROM tsk_vs_info")])
|
||||
return mapping
|
||||
|
||||
|
||||
def build_id_fs_info_table(db_cursor):
|
||||
def build_id_fs_info_table(db_cursor, isPostgreSQL):
|
||||
"""Build the map of object ids to fs_info.
|
||||
|
||||
Args:
|
||||
@ -516,10 +565,10 @@ def build_id_fs_info_table(db_cursor):
|
||||
"""
|
||||
# for each row in the db, take the object id, img_offset, and fs_type, then create a tuple in the dictionary
|
||||
# with the object id as the key and (img_offset + fs_type) as the value
|
||||
mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in db_cursor.execute("SELECT obj_id, img_offset, fs_type FROM tsk_fs_info")])
|
||||
mapping = dict([(row[0], str(row[1]) + '_' + str(row[2])) for row in sql_select_execute(db_cursor, isPostgreSQL, "SELECT obj_id, img_offset, fs_type FROM tsk_fs_info")])
|
||||
return mapping
|
||||
|
||||
def build_id_objects_table(db_cursor):
|
||||
def build_id_objects_table(db_cursor, isPostgreSQL):
|
||||
"""Build the map of object ids to par_id.
|
||||
|
||||
Args:
|
||||
@ -527,10 +576,10 @@ def build_id_objects_table(db_cursor):
|
||||
"""
|
||||
# for each row in the db, take the object id, par_obj_id, then create a tuple in the dictionary
|
||||
# with the object id as the key and par_obj_id, type as the value
|
||||
mapping = dict([(row[0], [row[1], row[2]]) for row in db_cursor.execute("SELECT * FROM tsk_objects")])
|
||||
mapping = dict([(row[0], [row[1], row[2]]) for row in sql_select_execute(db_cursor, isPostgreSQL, "SELECT * FROM tsk_objects")])
|
||||
return mapping
|
||||
|
||||
def build_id_artifact_types_table(db_cursor):
|
||||
def build_id_artifact_types_table(db_cursor, isPostgreSQL):
|
||||
"""Build the map of object ids to artifact ids.
|
||||
|
||||
Args:
|
||||
@ -538,7 +587,7 @@ def build_id_artifact_types_table(db_cursor):
|
||||
"""
|
||||
# for each row in the db, take the object id, par_obj_id, then create a tuple in the dictionary
|
||||
# with the object id as the key and artifact type as the value
|
||||
mapping = dict([(row[0], row[1]) for row in db_cursor.execute("SELECT blackboard_artifacts.artifact_obj_id, blackboard_artifact_types.type_name FROM blackboard_artifacts INNER JOIN blackboard_artifact_types ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id ")])
|
||||
mapping = dict([(row[0], row[1]) for row in sql_select_execute(db_cursor, isPostgreSQL, "SELECT blackboard_artifacts.artifact_obj_id, blackboard_artifact_types.type_name FROM blackboard_artifacts INNER JOIN blackboard_artifact_types ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id ")])
|
||||
return mapping
|
||||
|
||||
|
||||
@ -565,6 +614,27 @@ def build_id_obj_path_table(files_table, objects_table, artifacts_table):
|
||||
mapping[k] = path + "/" + artifacts_table[v[0]]
|
||||
return mapping
|
||||
|
||||
def db_connect(db_file, isMultiUser, pgSettings=None):
|
||||
if isMultiUser: # use PostgreSQL
|
||||
try:
|
||||
return psycopg2.connect("dbname=" + db_file + " user=" + pgSettings.username + " host=" + pgSettings.pgHost + " password=" + pgSettings.password), None
|
||||
except:
|
||||
print("Failed to connect to the database: " + db_file)
|
||||
else: # Sqlite
|
||||
# Make a copy that we can modify
|
||||
backup_db_file = TskDbDiff._get_tmp_file("tsk_backup_db", ".db")
|
||||
shutil.copy(db_file, backup_db_file)
|
||||
# We sometimes get situations with messed up permissions
|
||||
os.chmod (backup_db_file, 0o777)
|
||||
return sqlite3.connect(backup_db_file), backup_db_file
|
||||
|
||||
def sql_select_execute(cursor, isPostgreSQL, sql_stmt):
|
||||
if isPostgreSQL:
|
||||
cursor.execute(sql_stmt)
|
||||
return cursor.fetchall()
|
||||
else:
|
||||
return cursor.execute(sql_stmt)
|
||||
|
||||
def main():
|
||||
try:
|
||||
sys.argv.pop(0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user