mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 01:07:42 +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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.LocalFilesDataSource;
|
import org.sleuthkit.datamodel.LocalFilesDataSource;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskDataException;
|
import org.sleuthkit.datamodel.TskDataException;
|
||||||
@ -37,6 +39,7 @@ import org.sleuthkit.datamodel.TskDataException;
|
|||||||
*/
|
*/
|
||||||
class AddLocalFilesTask implements Runnable {
|
class AddLocalFilesTask implements Runnable {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(AddLocalFilesTask.class.getName());
|
||||||
private final String deviceId;
|
private final String deviceId;
|
||||||
private final String rootVirtualDirectoryName;
|
private final String rootVirtualDirectoryName;
|
||||||
private final List<String> localFilePaths;
|
private final List<String> localFilePaths;
|
||||||
@ -89,6 +92,7 @@ class AddLocalFilesTask implements Runnable {
|
|||||||
newDataSources.add(newDataSource.getRootDirectory());
|
newDataSources.add(newDataSource.getRootDirectory());
|
||||||
} catch (TskDataException | TskCoreException ex) {
|
} catch (TskDataException | TskCoreException ex) {
|
||||||
errors.add(ex.getMessage());
|
errors.add(ex.getMessage());
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Failed to add datasource: %s", ex.getMessage()), ex);
|
||||||
} finally {
|
} finally {
|
||||||
DataSourceProcessorCallback.DataSourceProcessorResult result;
|
DataSourceProcessorCallback.DataSourceProcessorResult result;
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
|
@ -377,7 +377,9 @@ public class Case {
|
|||||||
*
|
*
|
||||||
* @param eventNames The events the subscriber is interested in.
|
* @param eventNames The events the subscriber is interested in.
|
||||||
* @param subscriber The subscriber (PropertyChangeListener) to add.
|
* @param subscriber The subscriber (PropertyChangeListener) to add.
|
||||||
|
* @deprecated Use addEventTypeSubscriber instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static void addEventSubscriber(Set<String> eventNames, PropertyChangeListener subscriber) {
|
public static void addEventSubscriber(Set<String> eventNames, PropertyChangeListener subscriber) {
|
||||||
eventPublisher.addSubscriber(eventNames, subscriber);
|
eventPublisher.addSubscriber(eventNames, subscriber);
|
||||||
}
|
}
|
||||||
@ -385,9 +387,23 @@ public class Case {
|
|||||||
/**
|
/**
|
||||||
* Adds a subscriber to specific case events.
|
* 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.
|
* @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) {
|
public static void addEventSubscriber(String eventName, PropertyChangeListener subscriber) {
|
||||||
eventPublisher.addSubscriber(eventName, subscriber);
|
eventPublisher.addSubscriber(eventName, subscriber);
|
||||||
}
|
}
|
||||||
@ -412,6 +428,18 @@ public class Case {
|
|||||||
eventPublisher.removeSubscriber(eventNames, subscriber);
|
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
|
* Checks if a case display name is valid, i.e., does not include any
|
||||||
* characters that cannot be used in file names.
|
* characters that cannot be used in file names.
|
||||||
|
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.casemodule;
|
|||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
@ -49,7 +50,7 @@ final class CaseDeleteAction extends CallableSystemAction {
|
|||||||
CaseDeleteAction() {
|
CaseDeleteAction() {
|
||||||
putValue(Action.NAME, NbBundle.getMessage(CaseDeleteAction.class, "CTL_CaseDeleteAction"));
|
putValue(Action.NAME, NbBundle.getMessage(CaseDeleteAction.class, "CTL_CaseDeleteAction"));
|
||||||
this.setEnabled(false);
|
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);
|
setEnabled(null != evt.getNewValue() && UserPreferences.getMode() != UserPreferences.SelectedMode.REVIEW);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import java.awt.Dimension;
|
|||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.util.EnumSet;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
@ -42,7 +43,7 @@ final class CasePropertiesAction extends CallableSystemAction {
|
|||||||
CasePropertiesAction() {
|
CasePropertiesAction() {
|
||||||
putValue(Action.NAME, NbBundle.getMessage(CasePropertiesAction.class, "CTL_CasePropertiesAction"));
|
putValue(Action.NAME, NbBundle.getMessage(CasePropertiesAction.class, "CTL_CasePropertiesAction"));
|
||||||
this.setEnabled(false);
|
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());
|
setEnabled(null != evt.getNewValue());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,8 @@ import java.beans.PropertyChangeListener;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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 EVENT_CHANNEL_NAME = "%s-Collaboration-Monitor-Events"; //NON-NLS
|
||||||
private static final String COLLABORATION_MONITOR_EVENT = "COLLABORATION_MONITOR_EVENT"; //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 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 String PERIODIC_TASK_THREAD_NAME = "collab-monitor-periodic-tasks-%d"; //NON-NLS
|
||||||
private static final long HEARTBEAT_INTERVAL_MINUTES = 1;
|
private static final long HEARTBEAT_INTERVAL_MINUTES = 1;
|
||||||
@ -113,7 +113,7 @@ final class CollaborationMonitor {
|
|||||||
*/
|
*/
|
||||||
localTasksManager = new LocalTasksManager();
|
localTasksManager = new LocalTasksManager();
|
||||||
IngestManager.getInstance().addIngestJobEventListener(localTasksManager);
|
IngestManager.getInstance().addIngestJobEventListener(localTasksManager);
|
||||||
Case.addEventSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, localTasksManager);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start periodic tasks that:
|
* 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);
|
IngestManager.getInstance().removeIngestJobEventListener(localTasksManager);
|
||||||
|
|
||||||
if (null != eventPublisher) {
|
if (null != eventPublisher) {
|
||||||
|
@ -1524,9 +1524,11 @@ public abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
@Override
|
@Override
|
||||||
public void bulkInsertReferenceTypeEntries(Set<EamGlobalFileInstance> globalInstances, EamArtifact.Type contentType) throws EamDbException {
|
public void bulkInsertReferenceTypeEntries(Set<EamGlobalFileInstance> globalInstances, EamArtifact.Type contentType) throws EamDbException {
|
||||||
Connection conn = connect();
|
Connection conn = connect();
|
||||||
|
|
||||||
PreparedStatement bulkPs = null;
|
PreparedStatement bulkPs = null;
|
||||||
try {
|
try {
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
|
||||||
// FUTURE: have a separate global_files table for each Type.
|
// FUTURE: have a separate global_files table for each Type.
|
||||||
String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
|
String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
|
||||||
+ getConflictClause();
|
+ getConflictClause();
|
||||||
@ -1542,8 +1544,14 @@ public abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bulkPs.executeBatch();
|
bulkPs.executeBatch();
|
||||||
|
conn.commit();
|
||||||
} catch (SQLException ex) {
|
} 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 {
|
} finally {
|
||||||
EamDbUtil.closePreparedStatement(bulkPs);
|
EamDbUtil.closePreparedStatement(bulkPs);
|
||||||
EamDbUtil.closeConnection(conn);
|
EamDbUtil.closeConnection(conn);
|
||||||
|
@ -36,8 +36,11 @@ public interface EamDb {
|
|||||||
* @throws EamDbException
|
* @throws EamDbException
|
||||||
*/
|
*/
|
||||||
static EamDb getInstance() throws EamDbException {
|
static EamDb getInstance() throws EamDbException {
|
||||||
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
|
|
||||||
|
|
||||||
|
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.DISABLED;
|
||||||
|
if (EamDbUtil.useCentralRepo()) {
|
||||||
|
selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
|
||||||
|
}
|
||||||
switch (selectedPlatform) {
|
switch (selectedPlatform) {
|
||||||
case POSTGRESQL:
|
case POSTGRESQL:
|
||||||
return PostgresEamDb.getInstance();
|
return PostgresEamDb.getInstance();
|
||||||
@ -86,7 +89,8 @@ public interface EamDb {
|
|||||||
* @return Is the database enabled
|
* @return Is the database enabled
|
||||||
*/
|
*/
|
||||||
static boolean isEnabled() {
|
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
|
* To change this template file, choose Tools | Templates
|
||||||
* and open the template in the editor.
|
* and open the template in the editor.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.sleuthkit.autopsy.centralrepository.datamodel;
|
package org.sleuthkit.autopsy.centralrepository.datamodel;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@ -15,13 +14,17 @@ import java.util.List;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDb.SCHEMA_VERSION;
|
import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDb.SCHEMA_VERSION;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class EamDbUtil {
|
public class EamDbUtil {
|
||||||
|
|
||||||
private final static Logger LOGGER = Logger.getLogger(EamDbUtil.class.getName());
|
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.
|
* Close the prepared statement.
|
||||||
*
|
*
|
||||||
@ -72,11 +75,12 @@ public class EamDbUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert the default correlation types into the database.
|
* Insert the default correlation types into the database.
|
||||||
*
|
*
|
||||||
* @param conn Open connection to use.
|
* @param conn Open connection to use.
|
||||||
|
*
|
||||||
* @return true on success, else false
|
* @return true on success, else false
|
||||||
*/
|
*/
|
||||||
public static boolean insertDefaultCorrelationTypes(Connection conn) {
|
public static boolean insertDefaultCorrelationTypes(Connection conn) {
|
||||||
@ -104,7 +108,7 @@ public class EamDbUtil {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store the schema version into the db_info table.
|
* Store the schema version into the db_info table.
|
||||||
*
|
*
|
||||||
@ -112,6 +116,7 @@ public class EamDbUtil {
|
|||||||
* loaded.
|
* loaded.
|
||||||
*
|
*
|
||||||
* @param conn Open connection to use.
|
* @param conn Open connection to use.
|
||||||
|
*
|
||||||
* @return true on success, else false
|
* @return true on success, else false
|
||||||
*/
|
*/
|
||||||
public static boolean insertSchemaVersion(Connection conn) {
|
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.
|
* Query to see if the SCHEMA_VERSION is set in the db.
|
||||||
*
|
*
|
||||||
* @return true if set, else false.
|
* @return true if set, else false.
|
||||||
*/
|
*/
|
||||||
public static boolean schemaVersionIsSet(Connection conn) {
|
public static boolean schemaVersionIsSet(Connection conn) {
|
||||||
if (null == conn) {
|
if (null == conn) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultSet resultSet = null;
|
ResultSet resultSet = null;
|
||||||
try {
|
try {
|
||||||
Statement tester = conn.createStatement();
|
Statement tester = conn.createStatement();
|
||||||
@ -157,17 +162,38 @@ public class EamDbUtil {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the current settings and the validation query
|
* If the Central Repos use has been enabled.
|
||||||
* to test the connection to the database.
|
*
|
||||||
*
|
* @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.
|
* @return true if successfull query execution, else false.
|
||||||
*/
|
*/
|
||||||
public static boolean executeValidationQuery(Connection conn, String validationQuery) {
|
public static boolean executeValidationQuery(Connection conn, String validationQuery) {
|
||||||
if (null == conn) {
|
if (null == conn) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultSet resultSet = null;
|
ResultSet resultSet = null;
|
||||||
try {
|
try {
|
||||||
Statement tester = conn.createStatement();
|
Statement tester = conn.createStatement();
|
||||||
@ -183,22 +209,23 @@ public class EamDbUtil {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conver thte Type's DbTableName string to the *_instances table name.
|
* Conver thte Type's DbTableName string to the *_instances table name.
|
||||||
*
|
*
|
||||||
* @param type Correlation Type
|
* @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) {
|
public static String correlationTypeToInstanceTableName(EamArtifact.Type type) {
|
||||||
return type.getDbTableName() + "_instances";
|
return type.getDbTableName() + "_instances";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the Type's DbTableName string to the reference_* table name.
|
* Convert the Type's DbTableName string to the reference_* table name.
|
||||||
*
|
*
|
||||||
* @param type Correlation Type
|
* @param type Correlation Type
|
||||||
|
*
|
||||||
* @return Reference table name for this Type.
|
* @return Reference table name for this Type.
|
||||||
*/
|
*/
|
||||||
public static String correlationTypeToReferenceTableName(EamArtifact.Type type) {
|
public static String correlationTypeToReferenceTableName(EamArtifact.Type type) {
|
||||||
|
@ -72,8 +72,10 @@ public class PostgresEamDb extends AbstractSqlEamDb {
|
|||||||
public void shutdownConnections() throws EamDbException {
|
public void shutdownConnections() throws EamDbException {
|
||||||
try {
|
try {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
connectionPool.close();
|
if(connectionPool != null){
|
||||||
connectionPool = null; // force it to be re-created on next connect()
|
connectionPool.close();
|
||||||
|
connectionPool = null; // force it to be re-created on next connect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
throw new EamDbException("Failed to close existing database connections.", ex); // NON-NLS
|
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.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.InvalidPathException;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@ -93,7 +94,7 @@ public final class SqliteEamDbSettings {
|
|||||||
if (badTagsStr == null) {
|
if (badTagsStr == null) {
|
||||||
badTagsStr = DEFAULT_BAD_TAGS;
|
badTagsStr = DEFAULT_BAD_TAGS;
|
||||||
}
|
}
|
||||||
if(badTagsStr.isEmpty()){
|
if (badTagsStr.isEmpty()) {
|
||||||
badTags = new ArrayList<>();
|
badTags = new ArrayList<>();
|
||||||
} else {
|
} else {
|
||||||
badTags = new ArrayList<>(Arrays.asList(badTagsStr.split(",")));
|
badTags = new ArrayList<>(Arrays.asList(badTagsStr.split(",")));
|
||||||
@ -111,13 +112,13 @@ public final class SqliteEamDbSettings {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that the db directory path exists.
|
* Verify that the db directory path exists.
|
||||||
*
|
*
|
||||||
* @return true if exists, else false
|
* @return true if exists, else false
|
||||||
*/
|
*/
|
||||||
public boolean dbDirectoryExists() {
|
public boolean dbDirectoryExists() {
|
||||||
// Ensure dbDirectory is a valid directory
|
// Ensure dbDirectory is a valid directory
|
||||||
File dbDir = new File(getDbDirectory());
|
File dbDir = new File(getDbDirectory());
|
||||||
|
|
||||||
if (!dbDir.exists()) {
|
if (!dbDir.exists()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (!dbDir.isDirectory()) {
|
} else if (!dbDir.isDirectory()) {
|
||||||
@ -130,7 +131,7 @@ public final class SqliteEamDbSettings {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the db directory if it does not exist.
|
* Create the db directory if it does not exist.
|
||||||
*
|
*
|
||||||
* @return true is successfully created or already exists, else false
|
* @return true is successfully created or already exists, else false
|
||||||
*/
|
*/
|
||||||
public boolean createDbDirectory() {
|
public boolean createDbDirectory() {
|
||||||
@ -139,7 +140,7 @@ public final class SqliteEamDbSettings {
|
|||||||
File dbDir = new File(getDbDirectory());
|
File dbDir = new File(getDbDirectory());
|
||||||
Files.createDirectories(dbDir.toPath());
|
Files.createDirectories(dbDir.toPath());
|
||||||
LOGGER.log(Level.INFO, "sqlite directory did not exist, created it at {0}.", getDbDirectory()); // NON-NLS
|
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
|
LOGGER.log(Level.SEVERE, "Failed to create sqlite database directory.", ex); // NON-NLS
|
||||||
return false;
|
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.
|
* If the directory path does not exist, it will return null.
|
||||||
*
|
*
|
||||||
* @return Connection or null.
|
* @return Connection or null.
|
||||||
*/
|
*/
|
||||||
private Connection getEphemeralConnection() {
|
private Connection getEphemeralConnection() {
|
||||||
@ -186,9 +188,9 @@ public final class SqliteEamDbSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the current settings and the validation query
|
* Use the current settings and the validation query to test the connection
|
||||||
* to test the connection to the database.
|
* to the database.
|
||||||
*
|
*
|
||||||
* @return true if successfull connection, else false.
|
* @return true if successfull connection, else false.
|
||||||
*/
|
*/
|
||||||
public boolean verifyConnection() {
|
public boolean verifyConnection() {
|
||||||
@ -196,16 +198,16 @@ public final class SqliteEamDbSettings {
|
|||||||
if (null == conn) {
|
if (null == conn) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean result = EamDbUtil.executeValidationQuery(conn, VALIDATION_QUERY);
|
boolean result = EamDbUtil.executeValidationQuery(conn, VALIDATION_QUERY);
|
||||||
EamDbUtil.closeConnection(conn);
|
EamDbUtil.closeConnection(conn);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the current settings and the schema version query
|
* Use the current settings and the schema version query to test the
|
||||||
* to test the database schema.
|
* database schema.
|
||||||
*
|
*
|
||||||
* @return true if successfull connection, else false.
|
* @return true if successfull connection, else false.
|
||||||
*/
|
*/
|
||||||
public boolean verifyDatabaseSchema() {
|
public boolean verifyDatabaseSchema() {
|
||||||
@ -247,7 +249,6 @@ public final class SqliteEamDbSettings {
|
|||||||
|
|
||||||
// NOTE: The organizations will only have a small number of rows, so
|
// NOTE: The organizations will only have a small number of rows, so
|
||||||
// an index is probably not worthwhile.
|
// an index is probably not worthwhile.
|
||||||
|
|
||||||
StringBuilder createCasesTable = new StringBuilder();
|
StringBuilder createCasesTable = new StringBuilder();
|
||||||
createCasesTable.append("CREATE TABLE IF NOT EXISTS cases (");
|
createCasesTable.append("CREATE TABLE IF NOT EXISTS cases (");
|
||||||
createCasesTable.append("id integer primary key autoincrement NOT NULL,");
|
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
|
// NOTE: the db_info table currenly only has 1 row, so having an index
|
||||||
// provides no benefit.
|
// provides no benefit.
|
||||||
|
|
||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
conn = getEphemeralConnection();
|
conn = getEphemeralConnection();
|
||||||
@ -385,7 +385,7 @@ public final class SqliteEamDbSettings {
|
|||||||
for (EamArtifact.Type type : DEFAULT_CORRELATION_TYPES) {
|
for (EamArtifact.Type type : DEFAULT_CORRELATION_TYPES) {
|
||||||
reference_type_dbname = EamDbUtil.correlationTypeToReferenceTableName(type);
|
reference_type_dbname = EamDbUtil.correlationTypeToReferenceTableName(type);
|
||||||
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
|
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
|
||||||
|
|
||||||
stmt.execute(String.format(createArtifactInstancesTableTemplate.toString(), instance_type_dbname, instance_type_dbname));
|
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(instancesIdx1, instance_type_dbname, instance_type_dbname));
|
||||||
stmt.execute(String.format(instancesIdx2, 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(createReferenceTypesTableTemplate.toString(), reference_type_dbname, reference_type_dbname));
|
||||||
stmt.execute(String.format(referenceTypesIdx1, 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));
|
stmt.execute(String.format(referenceTypesIdx2, reference_type_dbname, reference_type_dbname));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS
|
LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS
|
||||||
@ -422,7 +422,7 @@ public final class SqliteEamDbSettings {
|
|||||||
EamDbUtil.closeConnection(conn);
|
EamDbUtil.closeConnection(conn);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isChanged() {
|
public boolean isChanged() {
|
||||||
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbName"); // NON-NLS
|
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbName"); // NON-NLS
|
||||||
String dbDirectoryString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbDirectory"); // NON-NLS
|
String dbDirectoryString = ModuleSettings.getConfigSetting("CentralRepository", "db.sqlite.dbDirectory"); // NON-NLS
|
||||||
|
@ -13,7 +13,7 @@ EamSqliteSettingsDialog.bnCancel.text=Cancel
|
|||||||
EamSqliteSettingsDialog.lbTestDatabase.text=
|
EamSqliteSettingsDialog.lbTestDatabase.text=
|
||||||
EamSqliteSettingsDialog.bnTestDatabase.text=Test Connection
|
EamSqliteSettingsDialog.bnTestDatabase.text=Test Connection
|
||||||
EamSqliteSettingsDialog.lbTestDatabaseWarning.text=
|
EamSqliteSettingsDialog.lbTestDatabaseWarning.text=
|
||||||
EamSqliteSettingsDialog.bnDatabasePathFileOpen.text=Open...
|
EamSqliteSettingsDialog.bnDatabasePathFileOpen.text=Browse...
|
||||||
EamSqliteSettingsDialog.tfDatabasePath.toolTipText=Filename and path to store SQLite db file
|
EamSqliteSettingsDialog.tfDatabasePath.toolTipText=Filename and path to store SQLite db file
|
||||||
EamSqliteSettingsDialog.tfDatabasePath.text=
|
EamSqliteSettingsDialog.tfDatabasePath.text=
|
||||||
EamSqliteSettingsDialog.lbDatabasePath.text=Database Path :
|
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.
|
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
|
EamSqliteSettingsDialog.bnOk.text=OK
|
||||||
EamPostgresSettingsDialog.bnSave.text=Save
|
EamPostgresSettingsDialog.bnSave.text=Save
|
||||||
EamDbSettingsDialog.pnDatabaseConnectionSettings.border.title=Database Settings
|
EamDbSettingsDialog.bnDatabasePathFileOpen.text=Browse...
|
||||||
EamDbSettingsDialog.rdioBnPostgreSQL.text=PostgreSQL
|
|
||||||
EamDbSettingsDialog.rdioBnSQLite.text=SQLite
|
|
||||||
EamDbSettingsDialog.bnDatabasePathFileOpen.text=Open...
|
|
||||||
EamDbSettingsDialog.tfDatabasePath.toolTipText=Filename and path to store SQLite db file
|
EamDbSettingsDialog.tfDatabasePath.toolTipText=Filename and path to store SQLite db file
|
||||||
EamDbSettingsDialog.tfDatabasePath.text=
|
EamDbSettingsDialog.tfDatabasePath.text=
|
||||||
EamDbSettingsDialog.lbDatabasePath.text=Database Path :
|
EamDbSettingsDialog.lbDatabasePath.text=Database Path :
|
||||||
EamDbSettingsDialog.rdioBnDisabled.text=Disabled
|
|
||||||
EamDbSettingsDialog.bnCancel.text=Cancel
|
EamDbSettingsDialog.bnCancel.text=Cancel
|
||||||
EamDbSettingsDialog.bnOk.text=OK
|
EamDbSettingsDialog.bnOk.text=OK
|
||||||
EamDbSettingsDialog.bnTest.text=Test
|
|
||||||
EamDbSettingsDialog.lbHostName.text=Host Name / IP :
|
EamDbSettingsDialog.lbHostName.text=Host Name / IP :
|
||||||
EamDbSettingsDialog.lbDatabaseName.text=Database name :
|
|
||||||
EamDbSettingsDialog.lbUserPassword.text=User Password :
|
EamDbSettingsDialog.lbUserPassword.text=User Password :
|
||||||
EamDbSettingsDialog.lbUserName.text=User Name :
|
EamDbSettingsDialog.lbUserName.text=User Name :
|
||||||
EamDbSettingsDialog.lbPort.text=Port :
|
EamDbSettingsDialog.lbPort.text=Port :
|
||||||
EamDbSettingsDialog.bnCreateDb.text=Create
|
|
||||||
EamDbSettingsDialog.pnSetupGuidance.border.title=Setup Guidance
|
|
||||||
GlobalSettingsPanel.pnDatabaseConfiguration.title=Database Configuration
|
GlobalSettingsPanel.pnDatabaseConfiguration.title=Database Configuration
|
||||||
GlobalSettingsPanel.lbDbPlatformTypeLabel.text=Type:
|
GlobalSettingsPanel.lbDbPlatformTypeLabel.text=Type:
|
||||||
GlobalSettingsPanel.lbDbNameLabel.text=Name:
|
GlobalSettingsPanel.lbDbNameLabel.text=Name:
|
||||||
|
@ -29,12 +29,11 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="1" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="pnSetupGuidance" max="32767" attributes="0"/>
|
<Component id="pnButtons" max="32767" attributes="0"/>
|
||||||
<Component id="pnDatabaseConnectionSettings" alignment="0" max="32767" attributes="0"/>
|
<Component id="pnSQLiteSettings" alignment="0" max="32767" attributes="0"/>
|
||||||
<Component id="pnButtons" alignment="1" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -43,303 +42,22 @@
|
|||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||||
<Component id="pnSetupGuidance" min="-2" max="-2" attributes="0"/>
|
<Component id="pnSQLiteSettings" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="32767" 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"/>
|
<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>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
</Layout>
|
</Layout>
|
||||||
<SubComponents>
|
<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">
|
<Container class="javax.swing.JPanel" name="pnButtons">
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" alignment="0" 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"/>
|
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
<Component id="bnOk" min="-2" max="-2" attributes="0"/>
|
<Component id="bnOk" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="-2" pref="11" 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="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
<Component id="lbCreateIcon" max="32767" attributes="0"/>
|
<Component id="bnOk" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="lbTestIcon" alignment="1" max="32767" attributes="0"/>
|
<Component id="bnCancel" alignment="3" min="-2" max="-2" 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>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
@ -391,40 +100,13 @@
|
|||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnOkActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnOkActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
</Component>
|
</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>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
<Container class="javax.swing.JPanel" name="pnSetupGuidance">
|
<Container class="javax.swing.JPanel" name="pnSQLiteSettings">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||||
<TitledBorder title="Setup Guidance">
|
<EtchetBorder/>
|
||||||
<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>
|
</Border>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
@ -434,55 +116,176 @@
|
|||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="jScrollPane1" max="32767" attributes="0"/>
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<EmptySpace max="-2" 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>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<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"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="jScrollPane1" min="-2" max="-2" attributes="0"/>
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
<EmptySpace max="32767" 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>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
</Layout>
|
</Layout>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
|
<Component class="javax.swing.JLabel" name="lbDatabasePath">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<Border info="null"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbDatabasePath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
</Component>
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
<Component class="javax.swing.JTextField" name="tfDatabasePath">
|
||||||
<SubComponents>
|
<Properties>
|
||||||
<Component class="javax.swing.JTextArea" name="taSetupGuidance">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<Properties>
|
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.tfDatabasePath.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
<Property name="editable" type="boolean" value="false"/>
|
</Property>
|
||||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<Color blue="f0" green="f0" red="f0" type="rgb"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.tfDatabasePath.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="columns" type="int" value="20"/>
|
</Properties>
|
||||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
</Component>
|
||||||
<Font name="Monospaced" size="12" style="0"/>
|
<Component class="javax.swing.JButton" name="bnDatabasePathFileOpen">
|
||||||
</Property>
|
<Properties>
|
||||||
<Property name="lineWrap" type="boolean" value="true"/>
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<Property name="rows" type="int" value="3"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.bnDatabasePathFileOpen.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
<Property name="tabSize" type="int" value="4"/>
|
</Property>
|
||||||
<Property name="wrapStyleWord" type="boolean" value="true"/>
|
</Properties>
|
||||||
<Property name="autoscrolls" type="boolean" value="false"/>
|
<Events>
|
||||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnDatabasePathFileOpenActionPerformed"/>
|
||||||
<Border info="null"/>
|
</Events>
|
||||||
</Property>
|
</Component>
|
||||||
<Property name="requestFocusEnabled" type="boolean" value="false"/>
|
<Component class="javax.swing.JLabel" name="lbHostName">
|
||||||
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
|
<Properties>
|
||||||
</Properties>
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
</Component>
|
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="EamDbSettingsDialog.lbHostName.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</SubComponents>
|
</Property>
|
||||||
</Container>
|
</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>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -25,6 +25,10 @@
|
|||||||
<Component id="pnDatabaseContentButtons" max="32767" attributes="0"/>
|
<Component id="pnDatabaseContentButtons" max="32767" attributes="0"/>
|
||||||
<Component id="tbOops" alignment="1" max="32767" attributes="0"/>
|
<Component id="tbOops" alignment="1" max="32767" attributes="0"/>
|
||||||
<Component id="pnDatabaseConfiguration" 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>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -33,13 +37,14 @@
|
|||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="1" 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"/>
|
<Component id="pnDatabaseConfiguration" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="tbOops" min="-2" max="-2" attributes="0"/>
|
<Component id="tbOops" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="pnDatabaseContentButtons" min="-2" pref="50" 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>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
@ -240,5 +245,15 @@
|
|||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</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>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -29,6 +29,8 @@ import org.sleuthkit.autopsy.events.AutopsyEvent;
|
|||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbPlatformEnum;
|
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.PostgresEamDbSettings;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteEamDbSettings;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteEamDbSettings;
|
||||||
|
|
||||||
@ -53,7 +55,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
addIngestJobEventsListener();
|
addIngestJobEventsListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Messages({"GlobalSettingsPanel.title=Central Repository Settings"})
|
@Messages({"GlobalSettingsPanel.title=Central Repository Settings",
|
||||||
|
"GlobalSettingsPanel.cbUseCentralRepo.text=Use a Central Repository"})
|
||||||
private void customizeComponents() {
|
private void customizeComponents() {
|
||||||
setName(Bundle.GlobalSettingsPanel_title());
|
setName(Bundle.GlobalSettingsPanel_title());
|
||||||
}
|
}
|
||||||
@ -85,6 +88,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
bnManageTags = new javax.swing.JButton();
|
bnManageTags = new javax.swing.JButton();
|
||||||
bnManageTypes = new javax.swing.JButton();
|
bnManageTypes = new javax.swing.JButton();
|
||||||
tbOops = new javax.swing.JTextField();
|
tbOops = new javax.swing.JTextField();
|
||||||
|
cbUseCentralRepo = new javax.swing.JCheckBox();
|
||||||
|
|
||||||
setName(""); // NOI18N
|
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.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N
|
||||||
tbOops.setBorder(null);
|
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);
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
@ -207,50 +218,65 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(pnDatabaseContentButtons, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(pnDatabaseContentButtons, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addComponent(tbOops, javax.swing.GroupLayout.Alignment.TRAILING)
|
.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())
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
.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)
|
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(pnDatabaseContentButtons, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.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
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void bnImportDatabaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnImportDatabaseActionPerformed
|
private void bnImportDatabaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnImportDatabaseActionPerformed
|
||||||
|
store();
|
||||||
ImportHashDatabaseDialog dialog = new ImportHashDatabaseDialog();
|
ImportHashDatabaseDialog dialog = new ImportHashDatabaseDialog();
|
||||||
firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
||||||
}//GEN-LAST:event_bnImportDatabaseActionPerformed
|
}//GEN-LAST:event_bnImportDatabaseActionPerformed
|
||||||
|
|
||||||
private void bnManageTagsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTagsActionPerformed
|
private void bnManageTagsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTagsActionPerformed
|
||||||
|
store();
|
||||||
ManageTagsDialog dialog = new ManageTagsDialog();
|
ManageTagsDialog dialog = new ManageTagsDialog();
|
||||||
firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
||||||
}//GEN-LAST:event_bnManageTagsActionPerformed
|
}//GEN-LAST:event_bnManageTagsActionPerformed
|
||||||
|
|
||||||
private void bnManageTypesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTypesActionPerformed
|
private void bnManageTypesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTypesActionPerformed
|
||||||
|
store();
|
||||||
ManageCorrelationPropertiesDialog dialog = new ManageCorrelationPropertiesDialog();
|
ManageCorrelationPropertiesDialog dialog = new ManageCorrelationPropertiesDialog();
|
||||||
firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
|
||||||
}//GEN-LAST:event_bnManageTypesActionPerformed
|
}//GEN-LAST:event_bnManageTypesActionPerformed
|
||||||
|
|
||||||
private void bnDbConfigureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDbConfigureActionPerformed
|
private void bnDbConfigureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDbConfigureActionPerformed
|
||||||
|
store();
|
||||||
EamDbSettingsDialog dialog = new EamDbSettingsDialog();
|
EamDbSettingsDialog dialog = new EamDbSettingsDialog();
|
||||||
load(); // reload db settings content and update buttons
|
load(); // reload db settings content and update buttons
|
||||||
}//GEN-LAST:event_bnDbConfigureActionPerformed
|
}//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
|
@Override
|
||||||
@Messages({"GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module."})
|
@Messages({"GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module."})
|
||||||
public void load() {
|
public void load() {
|
||||||
tbOops.setText("");
|
tbOops.setText("");
|
||||||
|
|
||||||
enableAllSubComponents(false);
|
enableAllSubComponents(false);
|
||||||
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
|
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
|
||||||
|
cbUseCentralRepo.setSelected(EamDbUtil.useCentralRepo()); // NON-NLS
|
||||||
switch (selectedPlatform) {
|
switch (selectedPlatform) {
|
||||||
case POSTGRESQL:
|
case POSTGRESQL:
|
||||||
PostgresEamDbSettings dbSettingsPg = new PostgresEamDbSettings();
|
PostgresEamDbSettings dbSettingsPg = new PostgresEamDbSettings();
|
||||||
@ -270,16 +296,16 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
lbDbPlatformValue.setText(EamDbPlatformEnum.DISABLED.toString());
|
lbDbPlatformValue.setText(EamDbPlatformEnum.DISABLED.toString());
|
||||||
lbDbNameValue.setText("");
|
lbDbNameValue.setText("");
|
||||||
lbDbLocationValue.setText("");
|
lbDbLocationValue.setText("");
|
||||||
enableDatabaseConfigureButton(true);
|
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected());
|
||||||
tbOops.setText(Bundle.GlobalSettingsPanel_validationerrMsg_mustConfigure());
|
tbOops.setText(Bundle.GlobalSettingsPanel_validationerrMsg_mustConfigure());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ingestStateUpdated();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void store() { // Click OK or Apply on Options Panel
|
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
|
@Override
|
||||||
public void saveSettings() { // Click OK on Global Settings Panel
|
public void saveSettings() { // Click OK on Global Settings Panel
|
||||||
|
store();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -334,7 +361,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
|
|
||||||
if (IngestManager.getInstance().isIngestRunning()) {
|
if (IngestManager.getInstance().isIngestRunning()) {
|
||||||
tbOops.setText(Bundle.GlobalSettingsPanel_validationErrMsg_ingestRunning());
|
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
|
* @return True
|
||||||
*/
|
*/
|
||||||
private boolean enableAllSubComponents(Boolean enable) {
|
private boolean enableAllSubComponents(Boolean enable) {
|
||||||
enableDatabaseConfigureButton(enable);
|
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && enable);
|
||||||
enableButtonSubComponents(enable);
|
enableButtonSubComponents(cbUseCentralRepo.isSelected() && enable);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,9 +389,18 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
*
|
*
|
||||||
* @return True
|
* @return True
|
||||||
*/
|
*/
|
||||||
private boolean enableDatabaseConfigureButton(Boolean enable) {
|
private void enableDatabaseConfigureButton(Boolean enable) {
|
||||||
bnDbConfigure.setEnabled(enable);
|
boolean ingestRunning = IngestManager.getInstance().isIngestRunning();
|
||||||
return true;
|
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
|
* @return True
|
||||||
*/
|
*/
|
||||||
private boolean enableButtonSubComponents(Boolean enable) {
|
private boolean enableButtonSubComponents(Boolean enable) {
|
||||||
bnManageTypes.setEnabled(enable);
|
boolean ingestRunning = IngestManager.getInstance().isIngestRunning();
|
||||||
bnImportDatabase.setEnabled(enable);
|
bnManageTypes.setEnabled(enable && !ingestRunning);
|
||||||
bnManageTags.setEnabled(enable);
|
bnImportDatabase.setEnabled(enable && !ingestRunning);
|
||||||
|
bnManageTags.setEnabled(enable && !ingestRunning);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,6 +424,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
private javax.swing.JButton bnImportDatabase;
|
private javax.swing.JButton bnImportDatabase;
|
||||||
private javax.swing.JButton bnManageTags;
|
private javax.swing.JButton bnManageTags;
|
||||||
private javax.swing.JButton bnManageTypes;
|
private javax.swing.JButton bnManageTypes;
|
||||||
|
private javax.swing.JCheckBox cbUseCentralRepo;
|
||||||
private javax.swing.JLabel lbDbLocationLabel;
|
private javax.swing.JLabel lbDbLocationLabel;
|
||||||
private javax.swing.JLabel lbDbLocationValue;
|
private javax.swing.JLabel lbDbLocationValue;
|
||||||
private javax.swing.JLabel lbDbNameLabel;
|
private javax.swing.JLabel lbDbNameLabel;
|
||||||
|
@ -72,6 +72,7 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
|
|||||||
|
|
||||||
private final JFileChooser fileChooser = new JFileChooser();
|
private final JFileChooser fileChooser = new JFileChooser();
|
||||||
private final static String LAST_FILE_PATH_KEY = "CentralRepositoryImport_Path"; // NON-NLS
|
private final static String LAST_FILE_PATH_KEY = "CentralRepositoryImport_Path"; // NON-NLS
|
||||||
|
private final int HASH_IMPORT_THRESHOLD = 10000;
|
||||||
private EamOrganization selectedOrg = null;
|
private EamOrganization selectedOrg = null;
|
||||||
private List<EamOrganization> orgs = null;
|
private List<EamOrganization> orgs = null;
|
||||||
private final Collection<JTextField> textBoxes;
|
private final Collection<JTextField> textBoxes;
|
||||||
@ -533,7 +534,8 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
|
|||||||
String errorMessage = Bundle.ImportHashDatabaseDialog_errorMessage_failedToOpenHashDbMsg(selectedFilePath);
|
String errorMessage = Bundle.ImportHashDatabaseDialog_errorMessage_failedToOpenHashDbMsg(selectedFilePath);
|
||||||
// Future, make UI handle more than the "FILES" type.
|
// Future, make UI handle more than the "FILES" type.
|
||||||
try {
|
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
|
// run in the background and close dialog
|
||||||
SwingUtilities.invokeLater(new ImportHashDatabaseWorker(selectedFilePath, knownStatus, globalSetID, contentType)::execute);
|
SwingUtilities.invokeLater(new ImportHashDatabaseWorker(selectedFilePath, knownStatus, globalSetID, contentType)::execute);
|
||||||
dispose();
|
dispose();
|
||||||
@ -629,6 +631,7 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int numLines = 0;
|
int numLines = 0;
|
||||||
|
LOGGER.log(Level.INFO, "Importing hash database {0}", file.getName());
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
progress.progress(++numLines);
|
progress.progress(++numLines);
|
||||||
|
|
||||||
@ -646,9 +649,16 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
|
|||||||
"");
|
"");
|
||||||
|
|
||||||
globalInstances.add(eamGlobalFileInstance);
|
globalInstances.add(eamGlobalFileInstance);
|
||||||
|
|
||||||
|
if(numLines % HASH_IMPORT_THRESHOLD == 0){
|
||||||
|
dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType);
|
||||||
|
globalInstances.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType);
|
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.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import static java.util.Objects.nonNull;
|
import static java.util.Objects.nonNull;
|
||||||
@ -153,7 +154,7 @@ public class ImageUtils {
|
|||||||
SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals); //NON-NLS
|
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.
|
//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.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
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")
|
@NbBundle.Messages("AbstractAbstractFileNode.addFileProperty.desc=no description")
|
||||||
private static final String NO_DESCR = AbstractAbstractFileNode_addFileProperty_desc();
|
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
|
* @param abstractFile file to wrap
|
||||||
*/
|
*/
|
||||||
@ -67,13 +72,14 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Listen for case events so that we can detect when case is closed
|
// Listen for case events so that we can detect when the case is closed
|
||||||
Case.addPropertyChangeListener(pcl);
|
// or when tags are added.
|
||||||
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeListeners() {
|
private void removeListeners() {
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||||
@ -95,7 +101,11 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
// If so, refresh our children.
|
// If so, refresh our children.
|
||||||
try {
|
try {
|
||||||
Children parentsChildren = getParentNode().getChildren();
|
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();
|
((ContentChildren) parentsChildren).refreshChildren();
|
||||||
parentsChildren.getNodesCount();
|
parentsChildren.getNodesCount();
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.TskData;
|
||||||
import org.sleuthkit.datamodel.TskException;
|
import org.sleuthkit.datamodel.TskException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,6 +90,47 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
|||||||
return super.getName();
|
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
|
* Return true if the underlying content object has children Useful for lazy
|
||||||
* loading.
|
* loading.
|
||||||
@ -103,7 +150,7 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
|||||||
|
|
||||||
return hasChildren;
|
return hasChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return ids of children of the underlying content. The ids can be treated
|
* Return ids of children of the underlying content. The ids can be treated
|
||||||
* as keys - useful for lazy loading.
|
* as keys - useful for lazy loading.
|
||||||
|
@ -25,31 +25,29 @@ import java.beans.PropertyChangeListener;
|
|||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.EnumSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.Children;
|
|
||||||
import org.openide.nodes.Node;
|
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.WeakListeners;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
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.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked;
|
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.ViewArtifactInTimelineAction;
|
||||||
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
@ -68,6 +66,11 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
|
public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactNode.class.getName());
|
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()
|
private static Cache<Long, Content> contentCache = CacheBuilder.newBuilder()
|
||||||
.expireAfterWrite(1, TimeUnit.MINUTES).
|
.expireAfterWrite(1, TimeUnit.MINUTES).
|
||||||
@ -76,7 +79,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
private final BlackboardArtifact artifact;
|
private final BlackboardArtifact artifact;
|
||||||
private Content associated = null;
|
private Content associated = null;
|
||||||
private List<NodeProperty<? extends Object>> customProperties;
|
private List<NodeProperty<? extends Object>> customProperties;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Artifact types which should have the full unique path of the associated
|
* Artifact types which should have the full unique path of the associated
|
||||||
* content as a property.
|
* content as a property.
|
||||||
@ -128,8 +131,9 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct blackboard artifact node from an artifact and using provided
|
* Construct blackboard artifact node from an artifact, overriding the
|
||||||
* icon
|
* standard icon with the one at the path provided.
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* @param artifact artifact to encapsulate
|
* @param artifact artifact to encapsulate
|
||||||
* @param iconPath icon to use for the artifact
|
* @param iconPath icon to use for the artifact
|
||||||
@ -138,19 +142,19 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
super(artifact, createLookup(artifact));
|
super(artifact, createLookup(artifact));
|
||||||
|
|
||||||
this.artifact = artifact;
|
this.artifact = artifact;
|
||||||
|
|
||||||
// Look for associated Content i.e. the source file for the artifact
|
// Look for associated Content i.e. the source file for the artifact
|
||||||
for (Content content : this.getLookup().lookupAll(Content.class)) {
|
for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
|
||||||
if ( (content != null) && (!(content instanceof BlackboardArtifact)) ){
|
if ((lookupContent != null) && (!(lookupContent instanceof BlackboardArtifact))) {
|
||||||
this.associated = content;
|
this.associated = lookupContent;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setName(Long.toString(artifact.getArtifactID()));
|
this.setName(Long.toString(artifact.getArtifactID()));
|
||||||
this.setDisplayName();
|
this.setDisplayName();
|
||||||
this.setIconBaseWithExtension(iconPath);
|
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
|
* @param artifact artifact to encapsulate
|
||||||
*/
|
*/
|
||||||
public BlackboardArtifactNode(BlackboardArtifact artifact) {
|
public BlackboardArtifactNode(BlackboardArtifact artifact) {
|
||||||
|
|
||||||
this(artifact, ExtractedContent.getIconFilePath(artifact.getArtifactTypeID()));
|
this(artifact, ExtractedContent.getIconFilePath(artifact.getArtifactTypeID()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeListeners() {
|
private void removeListeners() {
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlackboardArtifact getArtifact() {
|
public BlackboardArtifact getArtifact() {
|
||||||
return this.artifact;
|
return this.artifact;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"BlackboardArtifactNode.getAction.errorTitle=Error getting actions",
|
"BlackboardArtifactNode.getAction.errorTitle=Error getting actions",
|
||||||
@ -221,7 +224,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
*/
|
*/
|
||||||
private void setDisplayName() {
|
private void setDisplayName() {
|
||||||
String displayName = ""; //NON-NLS
|
String displayName = ""; //NON-NLS
|
||||||
|
|
||||||
// If this is a node for a keyword hit on an artifact, we set the
|
// 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"
|
// display name to be the artifact type name followed by " Artifact"
|
||||||
// e.g. "Messages 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.
|
// Do nothing since the display name will be set to the file name.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayName.isEmpty() && artifact != null) {
|
if (displayName.isEmpty() && artifact != null) {
|
||||||
displayName = artifact.getName();
|
displayName = artifact.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setDisplayName(displayName);
|
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
|
* @return source file/content name
|
||||||
*/
|
*/
|
||||||
public String getSrcName() {
|
public String getSrcName() {
|
||||||
|
|
||||||
String srcName = "";
|
String srcName = "";
|
||||||
if (associated != null) {
|
if (associated != null) {
|
||||||
srcName = associated.getName();
|
srcName = associated.getName();
|
||||||
}
|
}
|
||||||
return srcName;
|
return srcName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"BlackboardArtifactNode.createSheet.artifactType.displayName=Artifact Type",
|
"BlackboardArtifactNode.createSheet.artifactType.displayName=Artifact Type",
|
||||||
"BlackboardArtifactNode.createSheet.artifactType.name=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_ASSOCIATED_ARTIFACT.getTypeID()
|
||||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()
|
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()
|
||||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()) {
|
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()) {
|
||||||
}
|
} else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
|
||||||
else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
|
addEmailMsgProperty(map, attribute);
|
||||||
addEmailMsgProperty (map, attribute);
|
} 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));
|
map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
|
||||||
} else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID()
|
} else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID()
|
||||||
&& attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
|
&& attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
|
||||||
@ -496,8 +496,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
value = value.substring(0, 512);
|
value = value.substring(0, 512);
|
||||||
}
|
}
|
||||||
map.put(attribute.getAttributeType().getDisplayName(), value);
|
map.put(attribute.getAttributeType().getDisplayName(), value);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
|
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
|
* Fill map with EmailMsg properties, not all attributes are filled
|
||||||
*
|
*
|
||||||
* @param map map with preserved ordering, where property names/values
|
* @param map map with preserved ordering, where property names/values
|
||||||
* are put
|
* are put
|
||||||
* @param attribute attribute to check/fill as property
|
* @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();
|
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_CONTENT_RTF.getTypeID()
|
||||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID()
|
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID()
|
||||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID()
|
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID()
|
||||||
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()
|
|| attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()) {
|
||||||
) {
|
|
||||||
|
|
||||||
// do nothing
|
// 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();
|
String value = attribute.getDisplayString();
|
||||||
if (value.length() > 160) {
|
if (value.length() > 160) {
|
||||||
value = value.substring(0, 160) + "...";
|
value = value.substring(0, 160) + "...";
|
||||||
}
|
}
|
||||||
map.put(attribute.getAttributeType().getDisplayName(), value);
|
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));
|
map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
|
map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,6 +581,6 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(ContentNodeVisitor<T> v) {
|
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.beans.PropertyChangeListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
@ -88,13 +89,13 @@ public class DataSourcesNode extends DisplayableItemNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
|
||||||
reloadKeys();
|
reloadKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED), pcl);
|
||||||
currentKeys.clear();
|
currentKeys.clear();
|
||||||
setKeys(Collections.<Content>emptySet());
|
setKeys(Collections.<Content>emptySet());
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,11 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
@ -173,68 +175,69 @@ public class DeletedContent implements AutopsyVisitableItem {
|
|||||||
* Listens for case and ingest invest. Updates observers when events are
|
* Listens for case and ingest invest. Updates observers when events are
|
||||||
* fired. Other nodes are listening to this for changes.
|
* 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() {
|
DeletedContentsChildrenObservable() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeListeners() {
|
private void removeListeners() {
|
||||||
deleteObservers();
|
deleteObservers();
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||||
@Override
|
String eventType = evt.getPropertyName();
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
|
||||||
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
|
* Case is closed, do nothing.
|
||||||
* 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) {
|
|
||||||
/**
|
|
||||||
* 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.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -285,7 +286,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
emailResults.update();
|
emailResults.update();
|
||||||
emailResults.addObserver(this);
|
emailResults.addObserver(this);
|
||||||
}
|
}
|
||||||
@ -294,7 +295,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
emailResults.deleteObserver(this);
|
emailResults.deleteObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -251,14 +252,14 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
typeNodeList.clear();
|
typeNodeList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +310,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
public class TypeNode extends DisplayableItemNode {
|
public class TypeNode extends DisplayableItemNode {
|
||||||
|
|
||||||
private BlackboardArtifact.Type type;
|
private final BlackboardArtifact.Type type;
|
||||||
private long childCount = 0;
|
private long childCount = 0;
|
||||||
|
|
||||||
TypeNode(BlackboardArtifact.Type type) {
|
TypeNode(BlackboardArtifact.Type type) {
|
||||||
|
@ -22,9 +22,11 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.nodes.AbstractNode;
|
import org.openide.nodes.AbstractNode;
|
||||||
import org.openide.nodes.ChildFactory;
|
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
|
* Listens for case and ingest invest. Updates observers when events are
|
||||||
* fired. Size-based nodes are listening to this for changes.
|
* 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() {
|
FileSizeRootChildrenObservable() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeListeners() {
|
private void removeListeners() {
|
||||||
deleteObservers();
|
deleteObservers();
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||||
@Override
|
String eventType = evt.getPropertyName();
|
||||||
public void propertyChange(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
|
* Case is closed, do nothing.
|
||||||
* 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
|
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
||||||
// @@@ could check the size here and only fire off updates if we know the file meets the min size criteria
|
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||||
Case.getCurrentCase();
|
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||||
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
|
||||||
* Case is closed, do nothing.
|
* out. Currently, remote events may be received for a case
|
||||||
*/
|
* that is already closed.
|
||||||
}
|
*/
|
||||||
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|
try {
|
||||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
Case.getCurrentCase();
|
||||||
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
update();
|
||||||
|
} catch (IllegalStateException notUsed) {
|
||||||
/**
|
/**
|
||||||
* Checking for a current case is a stop gap measure
|
* Case is closed, do nothing.
|
||||||
* 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();
|
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||||
update();
|
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||||
} catch (IllegalStateException notUsed) {
|
if (evt.getNewValue() == null) {
|
||||||
/**
|
removeListeners();
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -21,10 +21,11 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.function.Function;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.apache.commons.lang.StringUtils;
|
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.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
|
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
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.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
@ -75,9 +74,11 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
private class FileTypesByExtObservable extends Observable {
|
private class FileTypesByExtObservable extends Observable {
|
||||||
|
|
||||||
private final PropertyChangeListener pcl;
|
private final PropertyChangeListener pcl;
|
||||||
|
private final Set<Case.Events> CASE_EVENTS_OF_INTEREST;
|
||||||
|
|
||||||
private FileTypesByExtObservable() {
|
private FileTypesByExtObservable() {
|
||||||
super();
|
super();
|
||||||
|
this.CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.CURRENT_CASE);
|
||||||
this.pcl = (PropertyChangeEvent evt) -> {
|
this.pcl = (PropertyChangeEvent evt) -> {
|
||||||
String eventType = evt.getPropertyName();
|
String eventType = evt.getPropertyName();
|
||||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
|
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
|
||||||
@ -109,15 +110,14 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeListeners() {
|
private void removeListeners() {
|
||||||
deleteObservers();
|
deleteObservers();
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update() {
|
private void update() {
|
||||||
|
@ -24,11 +24,13 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
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.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
|
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
@ -79,6 +80,8 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
|
|||||||
*/
|
*/
|
||||||
private final PropertyChangeListener pcl;
|
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
|
* 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,
|
* 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() {
|
private void removeListeners() {
|
||||||
deleteObservers();
|
deleteObservers();
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
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);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
populateHashMap();
|
populateHashMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -252,7 +253,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
hashsetResults.update();
|
hashsetResults.update();
|
||||||
hashsetResults.addObserver(this);
|
hashsetResults.addObserver(this);
|
||||||
}
|
}
|
||||||
@ -261,7 +262,7 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
hashsetResults.deleteObserver(this);
|
hashsetResults.deleteObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.Action;
|
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)
|
// Listen for ingest events so that we can detect new added files (e.g. carved)
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
// Listen for case events so that we can detect when case is closed
|
// 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() {
|
private void removeListeners() {
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
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.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
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
|
* nice methods for its startup and shutdown, so it seemed like a
|
||||||
* cleaner place to register the property change listener.
|
* cleaner place to register the property change listener.
|
||||||
*/
|
*/
|
||||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
|
||||||
@Override
|
String eventType = evt.getPropertyName();
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
|
||||||
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
|
* Even with the check above, it is still possible that
|
||||||
* different way of handling the closing of cases is worked
|
* the case will be closed in a different thread before
|
||||||
* out. Currently, remote events may be received for a case
|
* this code executes. If that happens, it is possible
|
||||||
* that is already closed.
|
* for the event to have a null oldValue.
|
||||||
*/
|
*/
|
||||||
try {
|
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
|
||||||
Case.getCurrentCase();
|
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())) {
|
||||||
* 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();
|
|
||||||
interestingResults.update();
|
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() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
interestingResults.update();
|
interestingResults.update();
|
||||||
interestingResults.addObserver(this);
|
interestingResults.addObserver(this);
|
||||||
}
|
}
|
||||||
@ -256,7 +254,7 @@ public class InterestingHits implements AutopsyVisitableItem {
|
|||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
interestingResults.deleteObserver(this);
|
interestingResults.deleteObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -455,7 +456,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
keywordResults.update();
|
keywordResults.update();
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
}
|
}
|
||||||
@ -464,7 +465,7 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
super.removeNotify();
|
super.removeNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,9 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Action;
|
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 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() {
|
ReportNodeFactory() {
|
||||||
Case.addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, (PropertyChangeEvent evt) -> {
|
||||||
String eventType = evt.getPropertyName();
|
String eventType = evt.getPropertyName();
|
||||||
if (eventType.equals(Case.Events.REPORT_ADDED.toString()) || eventType.equals(Case.Events.REPORT_DELETED.toString())) {
|
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.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
@ -118,6 +120,12 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
private class TagNameNodeFactory extends ChildFactory.Detachable<TagName> implements Observer {
|
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() {
|
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
@ -171,7 +179,7 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
tagResults.update();
|
tagResults.update();
|
||||||
tagResults.addObserver(this);
|
tagResults.addObserver(this);
|
||||||
}
|
}
|
||||||
@ -180,7 +188,7 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
|
||||||
tagResults.deleteObserver(this);
|
tagResults.deleteObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.Children;
|
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)
|
// Listen for ingest events so that we can detect new added files (e.g. carved)
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
// Listen for case events so that we can detect when case is closed
|
// 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() {
|
private void removeListeners() {
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
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.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -311,7 +312,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
protected void removeNotify() {
|
protected void removeNotify() {
|
||||||
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
IngestManager.getInstance().removeIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
|
||||||
Case.removePropertyChangeListener(pcl);
|
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
super.removeNotify();
|
super.removeNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +320,7 @@ final public class Accounts implements AutopsyVisitableItem {
|
|||||||
protected void addNotify() {
|
protected void addNotify() {
|
||||||
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
IngestManager.getInstance().addIngestJobEventListener(pcl);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
IngestManager.getInstance().addIngestModuleEventListener(pcl);
|
||||||
Case.addPropertyChangeListener(pcl);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
|
||||||
super.addNotify();
|
super.addNotify();
|
||||||
refreshKeys();
|
refreshKeys();
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import java.io.File;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
@ -129,8 +130,10 @@ final class AddRawImageTask implements Runnable {
|
|||||||
|
|
||||||
File imageFile = Paths.get(imageFilePath).toFile();
|
File imageFile = Paths.get(imageFilePath).toFile();
|
||||||
if (!imageFile.exists()) {
|
if (!imageFile.exists()) {
|
||||||
errorMessages.add(Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePath + Bundle.AddRawImageTask_for_device()
|
String errorMessage = Bundle.AddRawImageTask_image_critical_error_adding() + imageFilePath + Bundle.AddRawImageTask_for_device()
|
||||||
+ deviceId + Bundle.AddRawImageTask_image_notExisting());
|
+ deviceId + Bundle.AddRawImageTask_image_notExisting();
|
||||||
|
errorMessages.add(errorMessage);
|
||||||
|
logger.log(Level.SEVERE, errorMessage);
|
||||||
criticalErrorOccurred = true;
|
criticalErrorOccurred = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -173,7 +176,9 @@ final class AddRawImageTask implements Runnable {
|
|||||||
caseDatabase.addLayoutFiles(dataSource, fileRanges);
|
caseDatabase.addLayoutFiles(dataSource, fileRanges);
|
||||||
|
|
||||||
} catch (TskCoreException ex) {
|
} 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;
|
criticalErrorOccurred = true;
|
||||||
} finally {
|
} finally {
|
||||||
caseDatabase.releaseExclusiveLock();
|
caseDatabase.releaseExclusiveLock();
|
||||||
|
@ -26,6 +26,7 @@ import org.sleuthkit.autopsy.datamodel.DirectoryNode;
|
|||||||
import org.openide.nodes.FilterNode;
|
import org.openide.nodes.FilterNode;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.AbstractContentNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
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.Content;
|
||||||
import org.sleuthkit.datamodel.Directory;
|
import org.sleuthkit.datamodel.Directory;
|
||||||
import org.sleuthkit.datamodel.LayoutFile;
|
import org.sleuthkit.datamodel.LayoutFile;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
import org.sleuthkit.datamodel.TskException;
|
import org.sleuthkit.datamodel.TskException;
|
||||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
import org.sleuthkit.datamodel.Volume;
|
import org.sleuthkit.datamodel.Volume;
|
||||||
@ -120,7 +120,7 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
|||||||
&& !((Directory) c).getName().equals(".."))) {
|
&& !((Directory) c).getName().equals(".."))) {
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
} else if (c.hasChildren()) {
|
} else if(AbstractContentNode.contentHasVisibleContentChildren(c)){
|
||||||
//fie has children, such as derived files
|
//fie has children, such as derived files
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
@ -204,12 +204,8 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
|||||||
if ((childContent instanceof AbstractFile) && ((AbstractFile) childContent).isDir()) {
|
if ((childContent instanceof AbstractFile) && ((AbstractFile) childContent).isDir()) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
try {
|
if(AbstractContentNode.contentHasVisibleContentChildren(childContent)){
|
||||||
if (childContent.hasChildren()) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error checking if file node is leaf.", e); //NON-NLS
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,7 +240,6 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
|||||||
@Override
|
@Override
|
||||||
public Boolean visit(VirtualDirectoryNode vdn) {
|
public Boolean visit(VirtualDirectoryNode vdn) {
|
||||||
return visitDeep(vdn);
|
return visitDeep(vdn);
|
||||||
//return ! vdn.hasContentChildren();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -286,7 +281,7 @@ class DirectoryTreeFilterChildren extends FilterNode.Children {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean visit(FileNode fn) {
|
public Boolean visit(FileNode fn) {
|
||||||
return fn.hasContentChildren();
|
return fn.hasVisibleContentChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,7 +25,6 @@ import java.util.logging.Level;
|
|||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.FilterNode;
|
import org.openide.nodes.FilterNode;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.openide.util.lookup.ProxyLookup;
|
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.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.Directory;
|
import org.sleuthkit.datamodel.Directory;
|
||||||
import org.sleuthkit.datamodel.Image;
|
import org.sleuthkit.datamodel.Image;
|
||||||
@ -120,7 +120,7 @@ class DirectoryTreeFilterNode extends FilterNode {
|
|||||||
private int getVisibleChildCount(AbstractFile file) throws TskCoreException {
|
private int getVisibleChildCount(AbstractFile file) throws TskCoreException {
|
||||||
List<Content> childList = file.getChildren();
|
List<Content> childList = file.getChildren();
|
||||||
|
|
||||||
int numVisibleChildren = file.getChildrenCount();
|
int numVisibleChildren = childList.size();
|
||||||
boolean purgeKnownFiles = UserPreferences.hideKnownFilesInDataSourcesTree();
|
boolean purgeKnownFiles = UserPreferences.hideKnownFilesInDataSourcesTree();
|
||||||
boolean purgeSlackFiles = UserPreferences.hideSlackFilesInDataSourcesTree();
|
boolean purgeSlackFiles = UserPreferences.hideSlackFilesInDataSourcesTree();
|
||||||
|
|
||||||
@ -134,6 +134,14 @@ class DirectoryTreeFilterNode extends FilterNode {
|
|||||||
|| (purgeSlackFiles && childFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) {
|
|| (purgeSlackFiles && childFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) {
|
||||||
numVisibleChildren--;
|
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.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
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);
|
this.em.addPropertyChangeListener(this);
|
||||||
IngestManager.getInstance().addIngestJobEventListener(this);
|
IngestManager.getInstance().addIngestJobEventListener(this);
|
||||||
IngestManager.getInstance().addIngestModuleEventListener(this);
|
IngestManager.getInstance().addIngestModuleEventListener(this);
|
||||||
|
@ -56,3 +56,5 @@ SizeSearchPanel.sizeCompareComboBox.lessThan=less than
|
|||||||
MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected
|
MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected
|
||||||
FileSearchPanel.searchButton.text=Search
|
FileSearchPanel.searchButton.text=Search
|
||||||
MimeTypePanel.mimeTypeCheckBox.text=MIME Type:
|
MimeTypePanel.mimeTypeCheckBox.text=MIME Type:
|
||||||
|
HashSearchPanel.md5CheckBox.text=MD5:
|
||||||
|
HashSearchPanel.emptyHashMsg.text=Must enter something for hash search.
|
@ -28,6 +28,7 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
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 DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy");
|
||||||
private static final String SEPARATOR = "SEPARATOR"; //NON-NLS
|
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
|
* New DateSearchFilter with the default panel
|
||||||
*/
|
*/
|
||||||
@ -62,7 +66,7 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
|
|||||||
|
|
||||||
private DateSearchFilter(DateSearchPanel panel) {
|
private DateSearchFilter(DateSearchPanel panel) {
|
||||||
super(panel);
|
super(panel);
|
||||||
Case.addPropertyChangeListener(this.new CasePropertyChangeListener());
|
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, this.new CasePropertyChangeListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.filesearch;
|
|||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.util.EnumSet;
|
||||||
import org.openide.util.HelpCtx;
|
import org.openide.util.HelpCtx;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.actions.CallableSystemAction;
|
import org.openide.util.actions.CallableSystemAction;
|
||||||
@ -35,14 +35,10 @@ final class FileSearchAction extends CallableSystemAction implements FileSearchP
|
|||||||
FileSearchAction() {
|
FileSearchAction() {
|
||||||
super();
|
super();
|
||||||
setEnabled(Case.isCaseOpen());
|
setEnabled(Case.isCaseOpen());
|
||||||
Case.addPropertyChangeListener(new PropertyChangeListener() {
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||||
@Override
|
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
setEnabled(evt.getNewValue() != null);
|
||||||
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.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(), "FileSearchPanel.filterTitle.knownStatus"), new KnownStatusSearchFilter()));
|
||||||
|
|
||||||
|
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "HashSearchPanel.md5CheckBox.text"), new HashSearchFilter()));
|
||||||
|
|
||||||
for (FilterArea fa : this.filterAreas) {
|
for (FilterArea fa : this.filterAreas) {
|
||||||
fa.setMaximumSize(new Dimension(Integer.MAX_VALUE, fa.getMinimumSize().height));
|
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.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -229,7 +230,7 @@ public class IngestManager {
|
|||||||
* opened/closed) events.
|
* opened/closed) events.
|
||||||
*/
|
*/
|
||||||
private void subscribeToCaseEvents() {
|
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) {
|
if (event.getNewValue() != null) {
|
||||||
handleCaseOpened();
|
handleCaseOpened();
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,6 +25,7 @@ import java.awt.Font;
|
|||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.util.EnumSet;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.windows.Mode;
|
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())) {
|
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||||
setEnabled(evt.getNewValue() != null && RuntimeProperties.runningWithGUI());
|
setEnabled(evt.getNewValue() != null && RuntimeProperties.runningWithGUI());
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import java.awt.event.ActionListener;
|
|||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.logging.FileHandler;
|
import java.util.logging.FileHandler;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.SimpleFormatter;
|
import java.util.logging.SimpleFormatter;
|
||||||
@ -121,7 +122,7 @@ public final class IngestMonitor {
|
|||||||
|
|
||||||
MonitorTimerAction() {
|
MonitorTimerAction() {
|
||||||
findRootDirectoryForCurrentCase();
|
findRootDirectoryForCurrentCase();
|
||||||
Case.addEventSubscriber(Case.Events.CURRENT_CASE.toString(), (PropertyChangeEvent evt) -> {
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||||
if (evt instanceof AutopsyEvent) {
|
if (evt instanceof AutopsyEvent) {
|
||||||
AutopsyEvent event = (AutopsyEvent) evt;
|
AutopsyEvent event = (AutopsyEvent) evt;
|
||||||
if (AutopsyEvent.SourceType.LOCAL == event.getSourceType() && event.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
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.WindowAdapter;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.util.EnumSet;
|
||||||
import org.openide.util.HelpCtx;
|
import org.openide.util.HelpCtx;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.actions.CallableSystemAction;
|
import org.openide.util.actions.CallableSystemAction;
|
||||||
@ -43,13 +43,9 @@ class HashDbPanelSearchAction extends CallableSystemAction {
|
|||||||
HashDbPanelSearchAction() {
|
HashDbPanelSearchAction() {
|
||||||
super();
|
super();
|
||||||
setEnabled(Case.isCaseOpen());
|
setEnabled(Case.isCaseOpen());
|
||||||
Case.addPropertyChangeListener(new PropertyChangeListener() {
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
|
||||||
|
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||||
@Override
|
setEnabled(evt.getNewValue() != null);
|
||||||
public void propertyChange(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.awt.event.ActionListener;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
@ -81,7 +82,7 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr
|
|||||||
|
|
||||||
public ReportWizardAction() {
|
public ReportWizardAction() {
|
||||||
setEnabled(false);
|
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())) {
|
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
|
||||||
Case newCase = (Case) evt.getNewValue();
|
Case newCase = (Case) evt.getNewValue();
|
||||||
setEnabled(newCase != null && RuntimeProperties.runningWithGUI());
|
setEnabled(newCase != null && RuntimeProperties.runningWithGUI());
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
Note there is no namespace collision with ver 3 -->
|
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-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-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="log4j" name="log4j" rev="1.2.17"/>
|
||||||
|
|
||||||
<!-- <dependency conf="autopsy_core->*" org="org.jdom" name="jdom" rev="1.1.3"/> -->
|
<!-- <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-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-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.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-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-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
|
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.source=1.8
|
||||||
javac.compilerargs=-Xlint -Xlint:-serial
|
javac.compilerargs=-Xlint -Xlint:-serial
|
||||||
javadoc.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-javadoc.jar
|
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.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.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
|
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
|
javadoc.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4-javadoc.jar
|
||||||
nbm.needs.restart=true
|
nbm.needs.restart=true
|
||||||
source.reference.commons-csv-1.4.jar=release/modules/ext/commons-csv-1.4-sources.jar
|
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.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.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
|
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>
|
<runtime-relative-path>ext/sigar-1.6.4.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/sigar-1.6.4.jar</binary-origin>
|
<binary-origin>release/modules/ext/sigar-1.6.4.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/jna-3.4.0.jar</runtime-relative-path>
|
<runtime-relative-path>ext/jna-3.4.0.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/jna-3.4.0.jar</binary-origin>
|
<binary-origin>release/modules/ext/jna-3.4.0.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/gson-1.4.jar</runtime-relative-path>
|
<runtime-relative-path>ext/gson-1.4.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/gson-1.4.jar</binary-origin>
|
<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>
|
<runtime-relative-path>ext/imgscalr-lib-4.2.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/imgscalr-lib-4.2.jar</binary-origin>
|
<binary-origin>release/modules/ext/imgscalr-lib-4.2.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/common-io-3.2.jar</runtime-relative-path>
|
<runtime-relative-path>ext/common-io-3.2.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/common-io-3.2.jar</binary-origin>
|
<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>
|
<binary-origin>release/modules/ext/joda-time-2.4-javadoc.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/jcalendarbutton-1.4.6.jar</runtime-relative-path>
|
<runtime-relative-path>ext/poi-excelant-3.15.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/jcalendarbutton-1.4.6.jar</binary-origin>
|
<binary-origin>release/modules/ext/poi-excelant-3.15.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/poi-ooxml-3.15.jar</runtime-relative-path>
|
<runtime-relative-path>ext/jcalendarbutton-1.4.6.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/poi-ooxml-3.15.jar</binary-origin>
|
<binary-origin>release/modules/ext/jcalendarbutton-1.4.6.jar</binary-origin>
|
||||||
</class-path-extension>
|
</class-path-extension>
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/imageio-psd-3.2.jar</runtime-relative-path>
|
<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>
|
<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>
|
<binary-origin>release/modules/ext/stax-api-1.0.1.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/servlet-api-2.5.jar</runtime-relative-path>
|
<runtime-relative-path>ext/servlet-api-2.5.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/servlet-api-2.5.jar</binary-origin>
|
<binary-origin>release/modules/ext/servlet-api-2.5.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/imageio-pcx-3.2.jar</runtime-relative-path>
|
<runtime-relative-path>ext/imageio-pcx-3.2.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/imageio-pcx-3.2.jar</binary-origin>
|
<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>
|
<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>
|
<binary-origin>release/modules/ext/geronimo-jms_1.1_spec-1.0.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/joda-time-2.4-sources.jar</runtime-relative-path>
|
<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>
|
<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>
|
<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>
|
<binary-origin>release/modules/ext/jfxtras-fxml-8.0-r4.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/joda-time-2.4.jar</runtime-relative-path>
|
<runtime-relative-path>ext/joda-time-2.4.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/joda-time-2.4.jar</binary-origin>
|
<binary-origin>release/modules/ext/joda-time-2.4.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/commons-logging-1.1.2-javadoc.jar</runtime-relative-path>
|
<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>
|
<binary-origin>release/modules/ext/commons-logging-1.1.2-javadoc.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/slf4j-simple-1.6.1.jar</runtime-relative-path>
|
<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>
|
<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>
|
<runtime-relative-path>ext/guava-19.0.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/guava-19.0.jar</binary-origin>
|
<binary-origin>release/modules/ext/guava-19.0.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/imageio-bmp-3.2.jar</runtime-relative-path>
|
<runtime-relative-path>ext/imageio-bmp-3.2.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/imageio-bmp-3.2.jar</binary-origin>
|
<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>
|
<runtime-relative-path>ext/ant-1.8.2.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/ant-1.8.2.jar</binary-origin>
|
<binary-origin>release/modules/ext/ant-1.8.2.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/javassist-3.12.1.GA.jar</runtime-relative-path>
|
<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>
|
<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>
|
<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>
|
<binary-origin>release/modules/ext/commons-logging-1.1.2.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/controlsfx-8.40.11.jar</runtime-relative-path>
|
<runtime-relative-path>ext/controlsfx-8.40.11.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/controlsfx-8.40.11.jar</binary-origin>
|
<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>
|
<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>
|
<binary-origin>release/modules/ext/javaee-api-5.0-2.jar</binary-origin>
|
||||||
</class-path-extension>
|
</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>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/common-image-3.2.jar</runtime-relative-path>
|
<runtime-relative-path>ext/common-image-3.2.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/common-image-3.2.jar</binary-origin>
|
<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-Layer: org/sleuthkit/autopsy/experimental/autoingest/layer.xml
|
||||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
|
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
|
||||||
OpenIDE-Module-Requires: org.openide.windows.WindowManager
|
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>
|
</class-path-extension>
|
||||||
</data>
|
</data>
|
||||||
</configuration>
|
</configuration>
|
||||||
</project>
|
</project>
|
@ -145,6 +145,29 @@
|
|||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</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">
|
<Component class="javax.swing.JLabel" name="lbPending">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
<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}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.refreshButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.refreshButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="enabled" type="boolean" value="false"/>
|
<Property name="enabled" type="boolean" value="false"/>
|
||||||
@ -188,6 +212,119 @@
|
|||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
|
||||||
</Events>
|
</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>
|
||||||
<Component class="javax.swing.JLabel" name="lbServicesStatus">
|
<Component class="javax.swing.JLabel" name="lbServicesStatus">
|
||||||
<Properties>
|
<Properties>
|
||||||
@ -218,14 +355,26 @@
|
|||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.prioritizeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.prioritizeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
|
<<<<<<< HEAD
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<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}")"/>
|
<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>
|
||||||
<Property name="enabled" type="boolean" value="false"/>
|
<Property name="enabled" type="boolean" value="false"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<<<<<<< HEAD
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="prioritizeButtonActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="prioritizeButtonActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
|
=======
|
||||||
|
>>>>>>> upstream/develop
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import java.awt.Color;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -743,7 +744,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
}
|
}
|
||||||
}//GEN-LAST:event_prioritizeButtonActionPerformed
|
}//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.JScrollPane completedScrollPane;
|
||||||
private javax.swing.JTable completedTable;
|
private javax.swing.JTable completedTable;
|
||||||
private javax.swing.JLabel lbCompleted;
|
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.JScrollPane runningScrollPane;
|
||||||
private javax.swing.JTable runningTable;
|
private javax.swing.JTable runningTable;
|
||||||
private javax.swing.JTextField tbServicesStatusMessage;
|
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
|
* The enum is used in conjunction with the DefaultTableModel class to
|
||||||
|
@ -25,4 +25,8 @@
|
|||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
<<<<<<< HEAD
|
||||||
</Form>
|
</Form>
|
||||||
|
=======
|
||||||
|
</Form>
|
||||||
|
>>>>>>> upstream/develop
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011 - 2017 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,24 +18,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.netbeans.api.settings.ConvertAsProperties;
|
import java.util.stream.Collectors;
|
||||||
import org.openide.awt.ActionID;
|
|
||||||
import org.openide.awt.ActionReference;
|
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
import org.openide.windows.TopComponent;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.openide.windows.Mode;
|
import org.openide.windows.Mode;
|
||||||
|
import org.openide.windows.TopComponent;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Top component which displays the Auto Ingest Dashboard interface.
|
* Top component which displays the Auto Ingest Dashboard interface.
|
||||||
*/
|
*/
|
||||||
@ConvertAsProperties(
|
|
||||||
dtd = "-//org.sleuthkit.autopsy.experimental.autoingest//AutoIngestDashboard//EN",
|
|
||||||
autostore = false
|
|
||||||
)
|
|
||||||
@TopComponent.Description(
|
@TopComponent.Description(
|
||||||
preferredID = "AutoIngestDashboardTopComponent",
|
preferredID = "AutoIngestDashboardTopComponent",
|
||||||
//iconBase="SET/PATH/TO/ICON/HERE",
|
//iconBase="SET/PATH/TO/ICON/HERE",
|
||||||
@ -44,13 +38,11 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
@TopComponent.Registration(mode = "dashboard", openAtStartup = false)
|
@TopComponent.Registration(mode = "dashboard", openAtStartup = false)
|
||||||
@Messages({
|
@Messages({
|
||||||
"CTL_AutoIngestDashboardAction=Auto Ingest Dashboard",
|
"CTL_AutoIngestDashboardAction=Auto Ingest Dashboard",
|
||||||
"CTL_AutoIngestDashboardTopComponent=Auto Ingest Dashboard",
|
"CTL_AutoIngestDashboardTopComponent=Auto Ingest Dashboard"})
|
||||||
"HINT_AutoIngestDashboardTopComponent=This is an Auto Ingest Dashboard window"
|
|
||||||
})
|
|
||||||
public final class AutoIngestDashboardTopComponent extends TopComponent {
|
public final class AutoIngestDashboardTopComponent extends TopComponent {
|
||||||
|
|
||||||
public final static String PREFERRED_ID = "AutoIngestDashboardTopComponent"; // NON-NLS
|
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;
|
private static boolean topComponentInitialized = false;
|
||||||
|
|
||||||
public static void openTopComponent() {
|
public static void openTopComponent() {
|
||||||
@ -68,8 +60,11 @@ public final class AutoIngestDashboardTopComponent extends TopComponent {
|
|||||||
dashboard = AutoIngestDashboard.createDashboard();
|
dashboard = AutoIngestDashboard.createDashboard();
|
||||||
tc.add(dashboard);
|
tc.add(dashboard);
|
||||||
dashboard.setSize(dashboard.getPreferredSize());
|
dashboard.setSize(dashboard.getPreferredSize());
|
||||||
|
if (tc.isOpened() == false) {
|
||||||
tc.open();
|
tc.open();
|
||||||
tc.requestActive();
|
}
|
||||||
|
tc.toFront();
|
||||||
|
tc.requestActive();
|
||||||
} catch (AutoIngestDashboard.AutoIngestDashboardException ex) {
|
} catch (AutoIngestDashboard.AutoIngestDashboardException ex) {
|
||||||
// DLG: Catch the exeption, log it, and pop up an error dialog
|
// DLG: Catch the exeption, log it, and pop up an error dialog
|
||||||
// with a user-friendly message
|
// with a user-friendly message
|
||||||
@ -79,12 +74,12 @@ public final class AutoIngestDashboardTopComponent extends TopComponent {
|
|||||||
|
|
||||||
public static void closeTopComponent() {
|
public static void closeTopComponent() {
|
||||||
if (topComponentInitialized) {
|
if (topComponentInitialized) {
|
||||||
final TopComponent etc = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
|
final TopComponent tc = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
|
||||||
if (etc != null) {
|
if (tc != null) {
|
||||||
try {
|
try {
|
||||||
etc.close();
|
tc.close();
|
||||||
} catch (Exception e) {
|
} 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() {
|
public AutoIngestDashboardTopComponent() {
|
||||||
initComponents();
|
initComponents();
|
||||||
setName(Bundle.CTL_AutoIngestDashboardTopComponent());
|
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
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
// End of variables declaration//GEN-END: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
|
* back into hostNamesToRunningJobs as a result of
|
||||||
* processing the job status update.
|
* 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());
|
hostNamesToRunningJobs.remove(job.getNodeName());
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers(Event.JOB_COMPLETED);
|
notifyObservers(Event.JOB_COMPLETED);
|
||||||
|
@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
|||||||
*/
|
*/
|
||||||
final class AutoIngestSystemLogger {
|
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 int LOG_FILE_COUNT = 10;
|
||||||
private static final Logger LOGGER = Logger.getLogger("AutoIngest"); //NON-NLS
|
private static final Logger LOGGER = Logger.getLogger("AutoIngest"); //NON-NLS
|
||||||
private static final String NEWLINE = System.lineSeparator();
|
private static final String NEWLINE = System.lineSeparator();
|
||||||
|
@ -305,9 +305,13 @@ AutoIngestControlPanel.lbServicesStatus.text=Services Status:
|
|||||||
AutoIngestControlPanel.bnPrioritizeJob.actionCommand=<AutoIngestDashboard.bnPrioritizeJob.text>
|
AutoIngestControlPanel.bnPrioritizeJob.actionCommand=<AutoIngestDashboard.bnPrioritizeJob.text>
|
||||||
AutoIngestControlPanel.bnPrioritizeJob.toolTipText=Move this folder to the top of the Pending queue.
|
AutoIngestControlPanel.bnPrioritizeJob.toolTipText=Move this folder to the top of the Pending queue.
|
||||||
AutoIngestControlPanel.bnPrioritizeJob.text=Prioritize Job
|
AutoIngestControlPanel.bnPrioritizeJob.text=Prioritize Job
|
||||||
|
<<<<<<< HEAD
|
||||||
AutoIngestControlPanel.lbStatus.text=Status:
|
AutoIngestControlPanel.lbStatus.text=Status:
|
||||||
AutoIngestControlPanel.PauseDueToSystemError=Paused due to system error, please consult the auto ingest system log
|
AutoIngestControlPanel.PauseDueToSystemError=Paused due to system error, please consult the auto ingest system log
|
||||||
AutoIngestDashboard.prioritizeButton.toolTipText=Prioritizes the selected job
|
AutoIngestDashboard.prioritizeButton.toolTipText=Prioritizes the selected job
|
||||||
AutoIngestDashboard.prioritizeButton.text=&Prioritize
|
AutoIngestDashboard.prioritizeButton.text=&Prioritize
|
||||||
AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables
|
AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables
|
||||||
AutoIngestDashboard.refreshButton.text=&Refresh
|
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>
|
</file>
|
||||||
</folder>
|
</folder>
|
||||||
</folder>
|
</folder>
|
||||||
|
|
||||||
|
<folder name="Windows2">
|
||||||
|
<folder name="Modes">
|
||||||
|
<file name="dashboard.wsmode" url="dashboardWsmode.xml"/>
|
||||||
|
</folder>
|
||||||
|
</folder>
|
||||||
|
|
||||||
</filesystem>
|
</filesystem>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -73,7 +73,7 @@ class AccountsText implements IndexedText {
|
|||||||
private final long solrObjectId;
|
private final long solrObjectId;
|
||||||
private final Collection<? extends BlackboardArtifact> artifacts;
|
private final Collection<? extends BlackboardArtifact> artifacts;
|
||||||
private final Set<String> accountNumbers = new HashSet<>();
|
private final Set<String> accountNumbers = new HashSet<>();
|
||||||
private final String displayName;
|
private final String title;
|
||||||
|
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private boolean isPageInfoLoaded = false;
|
private boolean isPageInfoLoaded = false;
|
||||||
@ -105,7 +105,7 @@ class AccountsText implements IndexedText {
|
|||||||
AccountsText(long objectID, Collection<? extends BlackboardArtifact> artifacts) {
|
AccountsText(long objectID, Collection<? extends BlackboardArtifact> artifacts) {
|
||||||
this.solrObjectId = objectID;
|
this.solrObjectId = objectID;
|
||||||
this.artifacts = artifacts;
|
this.artifacts = artifacts;
|
||||||
displayName = artifacts.size() == 1
|
title = artifacts.size() == 1
|
||||||
? Bundle.AccountsText_creditCardNumber()
|
? Bundle.AccountsText_creditCardNumber()
|
||||||
: Bundle.AccountsText_creditCardNumbers();
|
: 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.
|
//add both the canonical form and the form in the text as accountNumbers to highlight.
|
||||||
this.accountNumbers.add(artifact.getAttribute(TSK_KEYWORD).getValueString());
|
BlackboardAttribute attribute = artifact.getAttribute(TSK_KEYWORD);
|
||||||
this.accountNumbers.add(artifact.getAttribute(TSK_CARD_NUMBER).getValueString());
|
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.
|
//if the chunk id is present just use that.
|
||||||
Optional<Integer> chunkID =
|
Optional<Integer> chunkID =
|
||||||
Optional.ofNullable(artifact.getAttribute(TSK_KEYWORD_SEARCH_DOCUMENT_ID))
|
Optional.ofNullable(artifact.getAttribute(TSK_KEYWORD_SEARCH_DOCUMENT_ID))
|
||||||
.map(BlackboardAttribute::getValueString)
|
.map(BlackboardAttribute::getValueString)
|
||||||
.map(String::trim)
|
.map(String::trim)
|
||||||
@ -245,10 +251,10 @@ class AccountsText implements IndexedText {
|
|||||||
needsQuery = true;
|
needsQuery = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsQuery) {
|
if (needsQuery) {
|
||||||
// Run a query to figure out which chunks for the current object have hits.
|
// 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)));
|
KeywordSearchQuery chunksQuery = KeywordSearchUtil.getQueryForKeyword(queryKeyword, new KeywordList(Arrays.asList(queryKeyword)));
|
||||||
chunksQuery.addFilter(new KeywordQueryFilter(KeywordQueryFilter.FilterType.CHUNK, this.solrObjectId));
|
chunksQuery.addFilter(new KeywordQueryFilter(KeywordQueryFilter.FilterType.CHUNK, this.solrObjectId));
|
||||||
//load the chunks/pages from the result of the query.
|
//load the chunks/pages from the result of the query.
|
||||||
@ -353,7 +359,7 @@ class AccountsText implements IndexedText {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return displayName;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.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.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>
|
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.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.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>
|
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.getSize.exception.msg=Cannot tell how many chars in converted string, until entire string is converted
|
||||||
AbstractFileStringContentStream.getSrcInfo.text=File\:{0}
|
AbstractFileStringContentStream.getSrcInfo.text=File\:{0}
|
||||||
ByteContentStream.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.nextPage.exception.msg=No next page.
|
||||||
ExtractedContentViewer.previousPage.exception.msg=No previous page.
|
ExtractedContentViewer.previousPage.exception.msg=No previous page.
|
||||||
ExtractedContentViewer.hasNextItem.exception.msg=Not supported, not a searchable source.
|
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.awt.event.MouseEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.event.PopupMenuEvent;
|
import javax.swing.event.PopupMenuEvent;
|
||||||
@ -76,7 +77,7 @@ class DropdownToolbar extends javax.swing.JPanel {
|
|||||||
private void customizeComponents() {
|
private void customizeComponents() {
|
||||||
searchSettingsChangeListener = new SearchSettingsChangeListener();
|
searchSettingsChangeListener = new SearchSettingsChangeListener();
|
||||||
KeywordSearch.getServer().addServerActionListener(searchSettingsChangeListener);
|
KeywordSearch.getServer().addServerActionListener(searchSettingsChangeListener);
|
||||||
Case.addPropertyChangeListener(searchSettingsChangeListener);
|
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), searchSettingsChangeListener);
|
||||||
|
|
||||||
DropdownListSearchPanel listsPanel = DropdownListSearchPanel.getDefault();
|
DropdownListSearchPanel listsPanel = DropdownListSearchPanel.getDefault();
|
||||||
listsPanel.addSearchButtonActionListener((ActionEvent e) -> {
|
listsPanel.addSearchButtonActionListener((ActionEvent e) -> {
|
||||||
|
@ -18,17 +18,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.keywordsearch;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import java.awt.ComponentOrientation;
|
import java.awt.ComponentOrientation;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.ItemListener;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JTextPane;
|
import javax.swing.JTextPane;
|
||||||
import javax.swing.SizeRequirements;
|
import javax.swing.SizeRequirements;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
@ -45,6 +43,7 @@ import org.openide.util.NbBundle;
|
|||||||
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.TextUtil;
|
import org.sleuthkit.autopsy.coreutils.TextUtil;
|
||||||
|
import static org.sleuthkit.autopsy.keywordsearch.Bundle.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panel displays HTML content sent to ExtractedContentViewer, and provides a
|
* 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 {
|
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() {
|
ExtractedContentPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
@ -124,32 +124,17 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
extractedTextPane.setEditorKit(editorKit);
|
extractedTextPane.setEditorKit(editorKit);
|
||||||
|
|
||||||
sourceComboBox.addItemListener(new ItemListener() {
|
sourceComboBox.addItemListener((ItemEvent e) -> {
|
||||||
@Override
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
public void itemStateChanged(ItemEvent e) {
|
setMarkup((IndexedText) e.getItem());
|
||||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
|
||||||
IndexedText source = (IndexedText) e.getItem();
|
|
||||||
setMarkup(source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setSources(new ArrayList<IndexedText>());
|
setSources("",new ArrayList<>());
|
||||||
|
|
||||||
extractedTextPane.setComponentPopupMenu(rightClickMenu);
|
extractedTextPane.setComponentPopupMenu(rightClickMenu);
|
||||||
ActionListener actList = new ActionListener() {
|
copyMenuItem.addActionListener(actionEvent -> extractedTextPane.copy());
|
||||||
@Override
|
selectAllMenuItem.addActionListener(actionEvent -> extractedTextPane.selectAll());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -364,8 +349,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
void refreshCurrentMarkup() {
|
void refreshCurrentMarkup() {
|
||||||
IndexedText ms = (IndexedText) sourceComboBox.getSelectedItem();
|
setMarkup(getSelectedSource());
|
||||||
setMarkup(ms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -374,13 +358,12 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
*
|
*
|
||||||
* @param sources
|
* @param sources
|
||||||
*/
|
*/
|
||||||
void setSources(List<IndexedText> sources) {
|
void setSources(String contentName, List<IndexedText> sources) {
|
||||||
|
this.contentName = contentName;
|
||||||
sourceComboBox.removeAllItems();
|
sourceComboBox.removeAllItems();
|
||||||
setPanelText(null, false);
|
setPanelText(null, false);
|
||||||
|
|
||||||
for (IndexedText ms : sources) {
|
sources.forEach(sourceComboBox::addItem);
|
||||||
sourceComboBox.addItem(ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sources.isEmpty()) {
|
if (!sources.isEmpty()) {
|
||||||
sourceComboBox.setSelectedIndex(0);
|
sourceComboBox.setSelectedIndex(0);
|
||||||
@ -411,9 +394,8 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setPanelText(String text, boolean detectDirection) {
|
private void setPanelText(String text, boolean detectDirection) {
|
||||||
if (text == null) {
|
|
||||||
text = "";
|
text = Strings.nullToEmpty(text);
|
||||||
}
|
|
||||||
|
|
||||||
if (detectDirection) {
|
if (detectDirection) {
|
||||||
//detect text direction using first 1024 chars and set it
|
//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
|
* text). Updates GUI in GUI thread and gets markup in background thread. To
|
||||||
* be invoked from GUI thread only.
|
* 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) {
|
private void setMarkup(IndexedText source) {
|
||||||
setPanelText(NbBundle.getMessage(this.getClass(), "ExtractedContentPanel.setMarkup.panelTxt"), false);
|
setPanelText(ExtractedContentPanel_setMarkup_panelTxt(), false);
|
||||||
new SetMarkupWorker(source).execute();
|
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 class SetMarkupWorker extends SwingWorker<String, Void> {
|
||||||
|
|
||||||
|
private final String contentName;
|
||||||
|
|
||||||
private final IndexedText source;
|
private final IndexedText source;
|
||||||
|
|
||||||
private ProgressHandle progress;
|
private ProgressHandle progress;
|
||||||
|
|
||||||
SetMarkupWorker(IndexedText source) {
|
SetMarkupWorker(String contentName,IndexedText source) {
|
||||||
|
this.contentName = contentName;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NbBundle.Messages({"# 0 - Content name","ExtractedContentPanel.SetMarkup.progress.loading=Loading text for {0}"})
|
||||||
protected String doInBackground() throws Exception {
|
protected String doInBackground() throws Exception {
|
||||||
progress = ProgressHandle.createHandle(NbBundle.getMessage(this.getClass(), "ExtractedContentPanel.SetMarkup.progress.loading"));
|
progress = ProgressHandle.createHandle(ExtractedContentPanel_SetMarkup_progress_loading(contentName));
|
||||||
progress.setDisplayName(NbBundle.getMessage(this.getClass(), "ExtractedContentPanel.SetMarkup.progress.displayName"));
|
|
||||||
progress.start();
|
progress.start();
|
||||||
progress.switchToIndeterminate();
|
progress.switchToIndeterminate();
|
||||||
|
|
||||||
|
@ -27,13 +27,13 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.ServiceProvider;
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
|
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT;
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
|
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
|
||||||
@ -91,7 +91,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Lookup nodeLookup = node.getLookup();
|
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
|
* Assemble a collection of all of the indexed text "sources" for the
|
||||||
@ -173,7 +173,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
panel.updateControls(currentSource);
|
panel.updateControls(currentSource);
|
||||||
setPanel(sources);
|
setPanel(content.getName(),sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException {
|
static private IndexedText getRawArtifactText(Lookup nodeLookup) throws TskCoreException {
|
||||||
@ -254,7 +254,7 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetComponent() {
|
public void resetComponent() {
|
||||||
setPanel(new ArrayList<>());
|
setPanel("",new ArrayList<>());
|
||||||
panel.resetDisplay();
|
panel.resetDisplay();
|
||||||
currentNode = null;
|
currentNode = null;
|
||||||
currentSource = null;
|
currentSource = null;
|
||||||
@ -312,9 +312,10 @@ public class ExtractedContentViewer implements DataContentViewer {
|
|||||||
*
|
*
|
||||||
* @param sources
|
* @param sources
|
||||||
*/
|
*/
|
||||||
private void setPanel(List<IndexedText> sources) {
|
private void setPanel(String contentName, List<IndexedText> sources) {
|
||||||
|
|
||||||
if (panel != null) {
|
if (panel != null) {
|
||||||
panel.setSources(sources);
|
panel.setSources(contentName, sources);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.keywordsearch;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to provide HTML text to display in ExtractedContentViewer. There is
|
* Interface to provide HTML text to display in ExtractedContentViewer. There is
|
||||||
* a SOLR implementation of this that interfaces with SOLR to highlight the
|
* a SOLR implementation of this that interfaces with SOLR to highlight the
|
||||||
@ -138,4 +136,5 @@ interface IndexedText {
|
|||||||
* @return the current item number
|
* @return the current item number
|
||||||
*/
|
*/
|
||||||
int currentItem();
|
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;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the fact that file or an artifact associated with a file had a keyword
|
* 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
|
* 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
|
* keyword was found and the object Id available to clients. Artifact keyword
|
||||||
* also make the artifact available to clients.
|
* hits also make the artifact available to clients.
|
||||||
*/
|
*/
|
||||||
class KeywordHit implements Comparable<KeywordHit> {
|
class KeywordHit implements Comparable<KeywordHit> {
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ class KeywordHit implements Comparable<KeywordHit> {
|
|||||||
private final long solrObjectId;
|
private final long solrObjectId;
|
||||||
private final int chunkId;
|
private final int chunkId;
|
||||||
private final String snippet;
|
private final String snippet;
|
||||||
private final Content content;
|
private final long contentID;
|
||||||
private final BlackboardArtifact artifact;
|
private final BlackboardArtifact artifact;
|
||||||
private final String hit;
|
private final String hit;
|
||||||
|
|
||||||
@ -44,14 +45,9 @@ class KeywordHit implements Comparable<KeywordHit> {
|
|||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeywordHit(String solrDocumentId, String snippet) throws TskCoreException {
|
|
||||||
this(solrDocumentId, snippet, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeywordHit(String solrDocumentId, String snippet, String hit) throws TskCoreException {
|
KeywordHit(String solrDocumentId, String snippet, String hit) throws TskCoreException {
|
||||||
/**
|
this.snippet = StringUtils.stripToEmpty(snippet);
|
||||||
* Store the Solr document id.
|
this.hit = hit;
|
||||||
*/
|
|
||||||
this.solrDocumentId = solrDocumentId;
|
this.solrDocumentId = solrDocumentId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,27 +68,19 @@ class KeywordHit implements Comparable<KeywordHit> {
|
|||||||
this.chunkId = 0;
|
this.chunkId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Look up the file associated with the keyword hit. If the high order
|
* If the high order bit of the object id is set (ie, it is negative),
|
||||||
* bit of the object id is set, the hit was for an artifact. In this
|
* the hit was in an artifact, look up the artifact.
|
||||||
* case, look up the artifact as well.
|
|
||||||
*/
|
*/
|
||||||
SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase();
|
|
||||||
long fileId;
|
|
||||||
if (this.solrObjectId < 0) {
|
if (this.solrObjectId < 0) {
|
||||||
|
SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase();
|
||||||
this.artifact = caseDb.getBlackboardArtifact(this.solrObjectId);
|
this.artifact = caseDb.getBlackboardArtifact(this.solrObjectId);
|
||||||
fileId = artifact.getObjectID();
|
contentID = artifact.getObjectID();
|
||||||
} else {
|
} else {
|
||||||
|
//else the object id is for content.
|
||||||
this.artifact = null;
|
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() {
|
String getSolrDocumentId() {
|
||||||
@ -103,24 +91,20 @@ class KeywordHit implements Comparable<KeywordHit> {
|
|||||||
return this.solrObjectId;
|
return this.solrObjectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasChunkId() {
|
|
||||||
return this.chunkId != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getChunkId() {
|
int getChunkId() {
|
||||||
return this.chunkId;
|
return this.chunkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasSnippet() {
|
boolean hasSnippet() {
|
||||||
return !this.snippet.isEmpty();
|
return StringUtils.isNotBlank(this.snippet);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getSnippet() {
|
String getSnippet() {
|
||||||
return this.snippet;
|
return this.snippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
Content getContent() {
|
long getContentID() {
|
||||||
return this.content;
|
return this.contentID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,7 +135,7 @@ class KeywordHit implements Comparable<KeywordHit> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final KeywordHit other = (KeywordHit) obj;
|
final KeywordHit other = (KeywordHit) obj;
|
||||||
return (this.solrObjectId == other.solrObjectId && this.chunkId == other.chunkId);
|
return this.compareTo(other) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -163,21 +147,8 @@ class KeywordHit implements Comparable<KeywordHit> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(KeywordHit o) {
|
public int compareTo(KeywordHit o) {
|
||||||
if (this.solrObjectId < o.solrObjectId) {
|
return Comparator.comparing(KeywordHit::getSolrObjectId)
|
||||||
// Out object id is less than the other object id
|
.thenComparing(KeywordHit::getChunkId)
|
||||||
return -1;
|
.compare(this, o);
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.keywordsearch;
|
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 {
|
interface KeywordSearchQuery {
|
||||||
|
|
||||||
@ -30,18 +33,20 @@ interface KeywordSearchQuery {
|
|||||||
*
|
*
|
||||||
* @return true if the query passed validation
|
* @return true if the query passed validation
|
||||||
*/
|
*/
|
||||||
boolean validate();
|
boolean validate();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* execute query and return results without publishing them return results
|
* execute query and return results without publishing them return results
|
||||||
* for all matching terms
|
* for all matching terms
|
||||||
*
|
*
|
||||||
* @throws KeywordSearchModuleException error while executing Solr term query
|
* @throws KeywordSearchModuleException error while executing Solr term
|
||||||
* @throws NoOpenCoreException if query failed due to server error, this
|
* query
|
||||||
* could be a notification to stop processing
|
* @throws NoOpenCoreException if query failed due to server error,
|
||||||
|
* this could be a notification to stop
|
||||||
|
* processing
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
QueryResults performQuery() throws KeywordSearchModuleException, NoOpenCoreException;
|
QueryResults performQuery() throws KeywordSearchModuleException, NoOpenCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an optional filter to narrow down the search Adding multiple filters
|
* 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
|
* @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
|
* Set an optional SOLR field to narrow down the search
|
||||||
*
|
*
|
||||||
* @param field field to set on the query
|
* @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
|
* Modify the query string to be searched as a substring instead of a whole
|
||||||
* word
|
* word
|
||||||
*
|
|
||||||
* @param isSubstring
|
|
||||||
*/
|
*/
|
||||||
void setSubstringQuery();
|
void setSubstringQuery();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* escape the query string and use the escaped string in the query
|
* escape the query string and use the escaped string in the query
|
||||||
*/
|
*/
|
||||||
void escape();
|
void escape();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return true if query was escaped
|
* @return true if query was escaped
|
||||||
*/
|
*/
|
||||||
boolean isEscaped();
|
boolean isEscaped();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return true if query is a literal query (non regex)
|
* @return true if query is a literal query (non regex)
|
||||||
*/
|
*/
|
||||||
boolean isLiteral();
|
boolean isLiteral();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return original keyword/query string
|
* return original keyword/query string
|
||||||
*
|
*
|
||||||
* @return the query String supplied originally
|
* @return the query String supplied originally
|
||||||
*/
|
*/
|
||||||
String getQueryString();
|
String getQueryString();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return escaped keyword/query string if escaping was done
|
* return escaped keyword/query string if escaping was done
|
||||||
*
|
*
|
||||||
* @return the escaped query string, or original string if no escaping done
|
* @return the escaped query string, or original string if no escaping done
|
||||||
*/
|
*/
|
||||||
String getEscapedQueryString();
|
String getEscapedQueryString();
|
||||||
|
|
||||||
KeywordCachedArtifact writeSingleFileHitsToBlackBoard(Keyword keyword, KeywordHit hit, String snippet, String listName);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
import com.google.common.collect.SetMultimap;
|
|
||||||
import com.google.common.collect.TreeMultimap;
|
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -41,6 +38,7 @@ import org.openide.nodes.Children;
|
|||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
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.datamodel.KeyValueNode;
|
||||||
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.KeyValueQueryContent;
|
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.KeyValueQueryContent;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
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;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW;
|
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP;
|
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP;
|
||||||
import org.sleuthkit.datamodel.Content;
|
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
|
* 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());
|
private static final Logger logger = Logger.getLogger(KeywordSearchResultFactory.class.getName());
|
||||||
|
|
||||||
//common properties (superset of all Node properties) to be displayed as columns
|
//common properties (superset of all Node properties) to be displayed as columns
|
||||||
static final List<String> COMMON_PROPERTIES
|
static final List<String> COMMON_PROPERTIES =
|
||||||
= Stream.concat(
|
Stream.concat(
|
||||||
Stream.of(
|
Stream.of(
|
||||||
TSK_KEYWORD,
|
TSK_KEYWORD,
|
||||||
TSK_KEYWORD_REGEXP,
|
TSK_KEYWORD_REGEXP,
|
||||||
TSK_KEYWORD_PREVIEW)
|
TSK_KEYWORD_PREVIEW)
|
||||||
.map(BlackboardAttribute.ATTRIBUTE_TYPE::getDisplayName),
|
.map(BlackboardAttribute.ATTRIBUTE_TYPE::getDisplayName),
|
||||||
Arrays.stream(AbstractAbstractFileNode.AbstractFilePropertyType.values())
|
Arrays.stream(AbstractAbstractFileNode.AbstractFilePropertyType.values())
|
||||||
.map(Object::toString))
|
.map(Object::toString))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
private final Collection<QueryRequest> queryRequests;
|
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
|
* properties are displayed as columns (since we are doing lazy child Node
|
||||||
* load we need to preinitialize properties when sending parent 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
|
@Override
|
||||||
protected boolean createKeys(List<KeyValueQueryContent> toPopulate) {
|
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());
|
MessageNotifyUtil.Notify.error(Bundle.KeywordSearchResultFactory_query_exception_msg() + queryRequest.getQueryString(), ex.getCause().getMessage());
|
||||||
return false;
|
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;
|
int hitNumber = 0;
|
||||||
List<KeyValueQueryContent> tempList = new ArrayList<>();
|
List<KeyValueQueryContent> tempList = new ArrayList<>();
|
||||||
@ -153,8 +159,20 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
|||||||
* Get file properties.
|
* Get file properties.
|
||||||
*/
|
*/
|
||||||
Map<String, Object> properties = new LinkedHashMap<>();
|
Map<String, Object> properties = new LinkedHashMap<>();
|
||||||
Content content = hit.getContent();
|
Content content = null;
|
||||||
String contentName = content.getName();
|
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) {
|
if (content instanceof AbstractFile) {
|
||||||
AbstractFsContentNode.fillPropertyMap(properties, (AbstractFile) content);
|
AbstractFsContentNode.fillPropertyMap(properties, (AbstractFile) content);
|
||||||
} else {
|
} 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
|
//wrap in KeywordSearchFilterNode for the markup content, might need to override FilterNode for more customization
|
||||||
return new KeywordSearchFilterNode(hits, kvNode);
|
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
|
* NOTE Parameters are defined based on how they are currently used in
|
||||||
* practice
|
* practice
|
||||||
*
|
*
|
||||||
* @param name File name that has hit.
|
* @param name File name that has hit.
|
||||||
* @param map Contains content metadata, snippets, etc. (property
|
* @param map Contains content metadata, snippets, etc.
|
||||||
* map)
|
* (property map)
|
||||||
* @param id User incremented ID
|
* @param id User incremented ID
|
||||||
* @param content File that had the hit.
|
* @param solrObjectId
|
||||||
* @param query Query used in search
|
* @param content File that had the hit.
|
||||||
* @param hits Full set of search results (for all files! @@@)
|
* @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) {
|
KeyValueQueryContent(String name, Map<String, Object> map, int id, long solrObjectId, Content content, KeywordSearchQuery query, QueryResults hits) {
|
||||||
super(name, map, id);
|
super(name, map, id);
|
||||||
@ -278,13 +298,12 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
|||||||
* worker for writing results to bb, with progress bar, cancellation, and
|
* worker for writing results to bb, with progress bar, cancellation, and
|
||||||
* central registry of workers to be stopped when case is closed
|
* 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 static final List<BlackboardResultWriter> writers = new ArrayList<>();
|
||||||
private ProgressHandle progress;
|
private ProgressHandle progress;
|
||||||
private final KeywordSearchQuery query;
|
private final KeywordSearchQuery query;
|
||||||
private final QueryResults hits;
|
private final QueryResults hits;
|
||||||
private Collection<BlackboardArtifact> newArtifacts = new ArrayList<>();
|
|
||||||
private static final int QUERY_DISPLAY_LEN = 40;
|
private static final int QUERY_DISPLAY_LEN = 40;
|
||||||
|
|
||||||
BlackboardResultWriter(QueryResults hits, String listName) {
|
BlackboardResultWriter(QueryResults hits, String listName) {
|
||||||
@ -298,13 +317,13 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object doInBackground() throws Exception {
|
protected Void doInBackground() throws Exception {
|
||||||
registerWriter(this); //register (synchronized on class) outside of writerLock to prevent deadlock
|
registerWriter(this); //register (synchronized on class) outside of writerLock to prevent deadlock
|
||||||
final String queryStr = query.getQueryString();
|
final String queryStr = query.getQueryString();
|
||||||
final String queryDisp = queryStr.length() > QUERY_DISPLAY_LEN ? queryStr.substring(0, QUERY_DISPLAY_LEN - 1) + " ..." : queryStr;
|
final String queryDisp = queryStr.length() > QUERY_DISPLAY_LEN ? queryStr.substring(0, QUERY_DISPLAY_LEN - 1) + " ..." : queryStr;
|
||||||
try {
|
try {
|
||||||
progress = ProgressHandle.createHandle(NbBundle.getMessage(this.getClass(), "KeywordSearchResultFactory.progress.saving", queryDisp), () -> BlackboardResultWriter.this.cancel(true));
|
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 {
|
} finally {
|
||||||
finalizeWorker();
|
finalizeWorker();
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.keywordsearch;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
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.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskException;
|
import org.sleuthkit.datamodel.TskException;
|
||||||
|
|
||||||
@ -192,15 +192,13 @@ class LuceneQuery implements KeywordSearchQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
|
||||||
|
|
||||||
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||||
BlackboardArtifact bba;
|
BlackboardArtifact bba;
|
||||||
KeywordCachedArtifact writeResult;
|
|
||||||
try {
|
try {
|
||||||
bba = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
bba = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||||
writeResult = new KeywordCachedArtifact(bba);
|
|
||||||
} catch (TskCoreException e) {
|
} catch (TskCoreException e) {
|
||||||
logger.log(Level.WARNING, "Error adding bb artifact for keyword hit", e); //NON-NLS
|
logger.log(Level.WARNING, "Error adding bb artifact for keyword hit", e); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
@ -233,8 +231,7 @@ class LuceneQuery implements KeywordSearchQuery {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
bba.addAttributes(attributes); //write out to bb
|
bba.addAttributes(attributes); //write out to bb
|
||||||
writeResult.add(attributes);
|
return bba;
|
||||||
return writeResult;
|
|
||||||
} catch (TskCoreException e) {
|
} catch (TskCoreException e) {
|
||||||
logger.log(Level.WARNING, "Error adding bb attributes to artifact", e); //NON-NLS
|
logger.log(Level.WARNING, "Error adding bb attributes to artifact", e); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
|
@ -31,6 +31,7 @@ import org.apache.commons.lang.StringUtils;
|
|||||||
import org.netbeans.api.progress.ProgressHandle;
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
import org.netbeans.api.progress.aggregate.ProgressContributor;
|
import org.netbeans.api.progress.aggregate.ProgressContributor;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||||
@ -40,6 +41,8 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.Content;
|
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
|
* 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<>();
|
private final Map<Keyword, List<KeywordHit>> results = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QueryResults(KeywordSearchQuery query) {
|
QueryResults(KeywordSearchQuery query) {
|
||||||
this.keywordSearchQuery = query;
|
this.keywordSearchQuery = query;
|
||||||
}
|
}
|
||||||
@ -70,8 +71,6 @@ class QueryResults {
|
|||||||
results.put(keyword, hits);
|
results.put(keyword, hits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
KeywordSearchQuery getQuery() {
|
KeywordSearchQuery getQuery() {
|
||||||
return keywordSearchQuery;
|
return keywordSearchQuery;
|
||||||
}
|
}
|
||||||
@ -99,7 +98,7 @@ class QueryResults {
|
|||||||
*
|
*
|
||||||
* @return The artifacts that were created.
|
* @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<>();
|
final Collection<BlackboardArtifact> newArtifacts = new ArrayList<>();
|
||||||
if (progress != null) {
|
if (progress != null) {
|
||||||
progress.start(getKeywords().size());
|
progress.start(getKeywords().size());
|
||||||
@ -145,14 +144,26 @@ class QueryResults {
|
|||||||
continue;
|
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) {
|
if (writeResult != null) {
|
||||||
newArtifacts.add(writeResult.getArtifact());
|
newArtifacts.add(writeResult);
|
||||||
if (notifyInbox) {
|
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 {
|
} 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;
|
++unitProgress;
|
||||||
@ -181,7 +192,6 @@ class QueryResults {
|
|||||||
* SolrObjectID-ChunkID pairs.
|
* SolrObjectID-ChunkID pairs.
|
||||||
*/
|
*/
|
||||||
private Collection<KeywordHit> getOneHitPerObject(Keyword keyword) {
|
private Collection<KeywordHit> getOneHitPerObject(Keyword keyword) {
|
||||||
|
|
||||||
HashMap<Long, KeywordHit> hits = new HashMap<>();
|
HashMap<Long, KeywordHit> hits = new HashMap<>();
|
||||||
|
|
||||||
// create a list of KeywordHits. KeywordHits with lowest chunkID is added the the list.
|
// 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 artifact The keyword hit artifact.
|
||||||
* @param hitFile
|
* @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 subjectSb = new StringBuilder();
|
||||||
StringBuilder detailsSb = new StringBuilder();
|
StringBuilder detailsSb = new StringBuilder();
|
||||||
|
|
||||||
@ -210,24 +224,24 @@ class QueryResults {
|
|||||||
} else {
|
} else {
|
||||||
subjectSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.kwHitLbl"));
|
subjectSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.kwHitLbl"));
|
||||||
}
|
}
|
||||||
|
|
||||||
String uniqueKey = null;
|
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) {
|
if (attr != null) {
|
||||||
final String keyword = attr.getValueString();
|
final String keyword = attr.getValueString();
|
||||||
subjectSb.append(keyword);
|
subjectSb.append(keyword);
|
||||||
uniqueKey = keyword.toLowerCase();
|
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
|
//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) {
|
if (attr != null) {
|
||||||
detailsSb.append("<tr>"); //NON-NLS
|
detailsSb.append("<tr>"); //NON-NLS
|
||||||
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.previewThLbl"));
|
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.previewThLbl"));
|
||||||
@ -247,16 +261,17 @@ class QueryResults {
|
|||||||
detailsSb.append("</tr>"); //NON-NLS
|
detailsSb.append("</tr>"); //NON-NLS
|
||||||
|
|
||||||
//list
|
//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) {
|
if (attr != null) {
|
||||||
detailsSb.append("<tr>"); //NON-NLS
|
detailsSb.append("<tr>"); //NON-NLS
|
||||||
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.listThLbl"));
|
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.listThLbl"));
|
||||||
detailsSb.append("<td>").append(attr.getValueString()).append("</td>"); //NON-NLS
|
detailsSb.append("<td>").append(attr.getValueString()).append("</td>"); //NON-NLS
|
||||||
detailsSb.append("</tr>"); //NON-NLS
|
detailsSb.append("</tr>"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
//regex
|
//regex
|
||||||
if (!keywordSearchQuery.isLiteral()) {
|
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) {
|
if (attr != null) {
|
||||||
detailsSb.append("<tr>"); //NON-NLS
|
detailsSb.append("<tr>"); //NON-NLS
|
||||||
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.regExThLbl"));
|
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.regExThLbl"));
|
||||||
@ -264,9 +279,9 @@ class QueryResults {
|
|||||||
detailsSb.append("</tr>"); //NON-NLS
|
detailsSb.append("</tr>"); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
detailsSb.append("</table>"); //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;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
import com.google.common.base.CharMatcher;
|
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.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -52,11 +48,9 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
import org.sleuthkit.datamodel.TskException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The RegexQuery class supports issuing regular expression queries against a
|
* 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 int MIN_EMAIL_ADDR_LENGTH = 8;
|
||||||
|
|
||||||
private final ListMultimap<Keyword, KeywordHit> hitsMultiMap = ArrayListMultimap.create();
|
|
||||||
|
|
||||||
// Lucene regular expressions do not support the following Java predefined
|
// Lucene regular expressions do not support the following Java predefined
|
||||||
// and POSIX character classes. There are other valid Java character classes
|
// 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.
|
// 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()));
|
solrQuery.setSort(SortClause.asc(Server.Schema.ID.toString()));
|
||||||
|
|
||||||
String cursorMark = CursorMarkParams.CURSOR_MARK_START;
|
String cursorMark = CursorMarkParams.CURSOR_MARK_START;
|
||||||
SolrDocumentList resultList ;
|
SolrDocumentList resultList;
|
||||||
boolean allResultsProcessed = false;
|
boolean allResultsProcessed = false;
|
||||||
|
QueryResults results = new QueryResults(this);
|
||||||
|
|
||||||
while (!allResultsProcessed) {
|
while (!allResultsProcessed) {
|
||||||
try {
|
try {
|
||||||
@ -204,9 +197,15 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
try {
|
try {
|
||||||
List<KeywordHit> keywordHits = createKeywordHits(resultDoc);
|
List<KeywordHit> keywordHits = createKeywordHits(resultDoc);
|
||||||
for (KeywordHit hit : keywordHits) {
|
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
|
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());
|
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;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,8 +283,8 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If searching for credit card account numbers, do a Luhn check
|
* If searching for credit card account numbers, do a Luhn
|
||||||
* on the term and discard it if it does not pass.
|
* check on the term and discard it if it does not pass.
|
||||||
*/
|
*/
|
||||||
if (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
if (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
|
||||||
Matcher ccnMatcher = CREDIT_CARD_NUM_PATTERN.matcher(hit);
|
Matcher ccnMatcher = CREDIT_CARD_NUM_PATTERN.matcher(hit);
|
||||||
@ -319,10 +315,14 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
throw ex;
|
throw ex;
|
||||||
} catch (Throwable error) {
|
} 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
|
* NOTE: Matcher.find() is known to throw StackOverflowError in rare
|
||||||
as a Throwable. When this occurs we should re-throw the error as TskCoreException so that it is
|
* cases (see JIRA-2700). StackOverflowError is an error, not an
|
||||||
logged by the calling method and move on to the next Solr document. */
|
* 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());
|
throw new TskCoreException("Failed to create keyword hits for Solr document id " + docId + " due to " + error.getMessage());
|
||||||
}
|
}
|
||||||
return hits;
|
return hits;
|
||||||
@ -373,50 +373,15 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
return escapedQuery;
|
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
|
@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();
|
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
|
* Create either a "plain vanilla" keyword hit artifact with keyword and
|
||||||
* regex attributes, or a credit card account artifact with attributes
|
* 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, MODULE_NAME, foundKeyword.getSearchTerm()));
|
||||||
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString()));
|
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString()));
|
||||||
try {
|
try {
|
||||||
newArtifact = hit.getContent().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
newArtifact = content.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||||
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
@ -455,7 +419,7 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
if (hit.isArtifactHit()) {
|
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
|
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 {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
@ -491,8 +455,8 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
* document id to support showing just the chunk that contained the
|
* document id to support showing just the chunk that contained the
|
||||||
* hit.
|
* hit.
|
||||||
*/
|
*/
|
||||||
if (hit.getContent() instanceof AbstractFile) {
|
if (content instanceof AbstractFile) {
|
||||||
AbstractFile file = (AbstractFile) hit.getContent();
|
AbstractFile file = (AbstractFile) content;
|
||||||
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|
||||||
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
|
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
|
||||||
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
|
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.
|
* Create an account artifact.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
newArtifact = hit.getContent().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT);
|
newArtifact = content.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
@ -524,9 +488,7 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
newArtifact.addAttributes(attributes);
|
newArtifact.addAttributes(attributes);
|
||||||
KeywordCachedArtifact writeResult = new KeywordCachedArtifact(newArtifact);
|
return newArtifact;
|
||||||
writeResult.add(attributes);
|
|
||||||
return writeResult;
|
|
||||||
} catch (TskCoreException e) {
|
} catch (TskCoreException e) {
|
||||||
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
@ -554,7 +516,7 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
* hit and turns them into artifact attributes. The track 1 data has the
|
* 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.
|
* 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.
|
* creating duplicate attributes.
|
||||||
* @param matcher A matcher for the snippet.
|
* @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
|
* 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.
|
* 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.
|
* creating duplicate attributes.
|
||||||
* @param attrType The type of attribute to create.
|
* @param attrType The type of attribute to create.
|
||||||
* @param groupName The group name of the regular expression that was
|
* @param groupName The group name of the regular expression that was
|
||||||
* used to parse the attribute data.
|
* used to parse the attribute data.
|
||||||
* @param matcher A matcher for the snippet.
|
* @param matcher A matcher for the snippet.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
static private void addAttributeIfNotAlreadyCaptured(Map<BlackboardAttribute.Type, BlackboardAttribute> attributeMap, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String groupName, Matcher matcher) {
|
static private void addAttributeIfNotAlreadyCaptured(Map<BlackboardAttribute.Type, BlackboardAttribute> attributeMap, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String groupName, Matcher matcher) {
|
||||||
BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrType);
|
BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrType);
|
||||||
@ -589,5 +552,4 @@ final class RegexQuery implements KeywordSearchQuery {
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
package org.sleuthkit.autopsy.keywordsearch;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -46,7 +45,6 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|||||||
import org.sleuthkit.autopsy.coreutils.StopWatch;
|
import org.sleuthkit.autopsy.coreutils.StopWatch;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton keyword search manager: Launches search threads for each job and
|
* Singleton keyword search manager: Launches search threads for each job and
|
||||||
@ -482,9 +480,7 @@ public final class SearchRunner {
|
|||||||
if (!newResults.getKeywords().isEmpty()) {
|
if (!newResults.getKeywords().isEmpty()) {
|
||||||
|
|
||||||
// Write results to BB
|
// 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
|
//scale progress bar more more granular, per result sub-progress, within per keyword
|
||||||
int totalUnits = newResults.getKeywords().size();
|
int totalUnits = newResults.getKeywords().size();
|
||||||
subProgresses[keywordsSearched].start(totalUnits);
|
subProgresses[keywordsSearched].start(totalUnits);
|
||||||
@ -496,7 +492,7 @@ public final class SearchRunner {
|
|||||||
subProgresses[keywordsSearched].progress(keywordList.getName() + ": " + queryDisplayStr, unitProgress);
|
subProgresses[keywordsSearched].progress(keywordList.getName() + ": " + queryDisplayStr, unitProgress);
|
||||||
|
|
||||||
// Create blackboard artifacts
|
// Create blackboard artifacts
|
||||||
newArtifacts = newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages());
|
newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages());
|
||||||
|
|
||||||
} //if has results
|
} //if has results
|
||||||
|
|
||||||
|
@ -824,7 +824,7 @@ public class Server {
|
|||||||
|
|
||||||
return new Core(coreName, theCase.getCaseType(), index);
|
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);
|
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
|
// 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
|
// core in it, and is only good for core-specific operations
|
||||||
private final HttpSolrServer solrCore;
|
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) {
|
private Core(String name, CaseType caseType, Index index) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -1240,7 +1242,8 @@ public class Server {
|
|||||||
this.solrCore = new HttpSolrServer(currentSolrServer.getBaseURL() + "/" + name); //NON-NLS
|
this.solrCore = new HttpSolrServer(currentSolrServer.getBaseURL() + "/" + name); //NON-NLS
|
||||||
|
|
||||||
//TODO test these settings
|
//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.setConnectionTimeout(1000);
|
||||||
solrCore.setDefaultMaxConnectionsPerHost(2);
|
solrCore.setDefaultMaxConnectionsPerHost(2);
|
||||||
solrCore.setMaxTotalConnections(5);
|
solrCore.setMaxTotalConnections(5);
|
||||||
|
@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
|||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
|||||||
+ "(?:\\?" // end sentinal: ? //NON-NLS
|
+ "(?:\\?" // end sentinal: ? //NON-NLS
|
||||||
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
|
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
|
||||||
+ "?)?)?)?)?)?");//close nested optional groups //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 :;<=>?
|
* Track 2 is numeric plus six punctuation symbolls :;<=>?
|
||||||
*
|
*
|
||||||
@ -115,7 +116,7 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
|||||||
+ "(?:[:;<=>?]" //end sentinel //NON-NLS
|
+ "(?:[:;<=>?]" //end sentinel //NON-NLS
|
||||||
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
|
+ "(?<LRC>.)" //longitudinal redundancy check //NON-NLS
|
||||||
+ "?)?)?)?)?)?"); //close nested optional groups //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
|
* 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));
|
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
|
@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
|
* Create either a "plain vanilla" keyword hit artifact with keyword and
|
||||||
* regex attributes, or a credit card account artifact with attributes
|
* 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) {
|
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, MODULE_NAME, foundKeyword.getSearchTerm()));
|
||||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
|
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
||||||
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
|
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()) {
|
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
|
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 {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
@ -411,8 +397,8 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
|||||||
* document id to support showing just the chunk that contained the
|
* document id to support showing just the chunk that contained the
|
||||||
* hit.
|
* hit.
|
||||||
*/
|
*/
|
||||||
if (hit.getContent() instanceof AbstractFile) {
|
if (content instanceof AbstractFile) {
|
||||||
AbstractFile file = (AbstractFile) hit.getContent();
|
AbstractFile file = (AbstractFile)content;
|
||||||
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|
||||||
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
|
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
|
||||||
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
|
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.
|
* Create an account artifact.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
|
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
@ -442,12 +428,10 @@ final class TermsComponentQuery implements KeywordSearchQuery {
|
|||||||
|
|
||||||
// TermsComponentQuery is now being used exclusively for substring searches.
|
// 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()));
|
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.SUBSTRING.ordinal()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
newArtifact.addAttributes(attributes);
|
newArtifact.addAttributes(attributes);
|
||||||
KeywordCachedArtifact writeResult = new KeywordCachedArtifact(newArtifact);
|
return newArtifact;
|
||||||
writeResult.add(attributes);
|
|
||||||
return writeResult;
|
|
||||||
} catch (TskCoreException e) {
|
} catch (TskCoreException e) {
|
||||||
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error adding bb attributes for terms search artifact", e); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
|
@ -94,6 +94,7 @@ public class AutopsyTestCases {
|
|||||||
|
|
||||||
public void testNewCaseWizardOpen(String title) {
|
public void testNewCaseWizardOpen(String title) {
|
||||||
logger.info("New Case");
|
logger.info("New Case");
|
||||||
|
resetTimeouts("WindowWaiter.WaitWindowTimeout", 240000);
|
||||||
NbDialogOperator nbdo = new NbDialogOperator(title);
|
NbDialogOperator nbdo = new NbDialogOperator(title);
|
||||||
JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button
|
JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button
|
||||||
jbo.pushNoBlock();
|
jbo.pushNoBlock();
|
||||||
@ -121,8 +122,8 @@ public class AutopsyTestCases {
|
|||||||
*/
|
*/
|
||||||
new Timeout("pausing", 120000).sleep();
|
new Timeout("pausing", 120000).sleep();
|
||||||
logger.info("Starting Add Image process");
|
logger.info("Starting Add Image process");
|
||||||
|
resetTimeouts("WindowWaiter.WaitWindowTimeOut", 240000);
|
||||||
WizardOperator wo = new WizardOperator("Add Data Source");
|
WizardOperator wo = new WizardOperator("Add Data Source");
|
||||||
wo.setTimeouts(resetTimeouts("WindowWaiter.WaitWindowTimeOut", 240000));
|
|
||||||
while(!wo.btNext().isEnabled()){
|
while(!wo.btNext().isEnabled()){
|
||||||
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
|
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 {
|
public void testGenerateReportButton() throws IOException {
|
||||||
logger.info("Generate Report Button");
|
logger.info("Generate Report Button");
|
||||||
|
resetTimeouts("ComponentOperator.WaitComponentTimeout", 240000);
|
||||||
JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false);
|
JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false);
|
||||||
JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog);
|
JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog);
|
||||||
JListOperator listOperator = new JListOperator(reportDialogOperator);
|
JListOperator listOperator = new JListOperator(reportDialogOperator);
|
||||||
@ -307,12 +309,10 @@ public class AutopsyTestCases {
|
|||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
String datenotime = dateFormat.format(date);
|
String datenotime = dateFormat.format(date);
|
||||||
listOperator.clickOnItem(0, 1);
|
listOperator.clickOnItem(0, 1);
|
||||||
new Timeout("pausing", 2000).sleep();
|
|
||||||
jbo0.pushNoBlock();
|
jbo0.pushNoBlock();
|
||||||
new Timeout("pausing", 2000).sleep();
|
new Timeout("pausing", 2000).sleep();
|
||||||
JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish");
|
JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish");
|
||||||
jbo1.pushNoBlock();
|
jbo1.pushNoBlock();
|
||||||
new Timeout("pausing", 1000).sleep();
|
|
||||||
JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false);
|
JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false);
|
||||||
screenshot("Progress");
|
screenshot("Progress");
|
||||||
JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog);
|
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 -->
|
<!-- Update configuration file to include jre -->
|
||||||
<property name="inst.property.file" value="${inst-path}/etc/${app.name}.conf" />
|
<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 -->
|
<!-- 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}">
|
<propertyfile file="${inst.property.file}">
|
||||||
<!-- Note: can be higher on 64 bit systems, should be in sync with project.properties -->
|
<!-- Note: can be higher on 64 bit systems, should be in sync with project.properties -->
|
||||||
<entry key="default_options" value="@JVM_OPTIONS" />
|
<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" />
|
<property name="app.property.file" value="${zip-tmp}/${app.name}/etc/${app.name}.conf" />
|
||||||
<!-- for Japanese localized version add option: -Duser.language=ja -->
|
<!-- 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}">
|
<propertyfile file="${app.property.file}">
|
||||||
<!-- Note: can be higher on 64 bit systems, should be in sync with project.properties -->
|
<!-- Note: can be higher on 64 bit systems, should be in sync with project.properties -->
|
||||||
<entry key="default_options" value="@JVM_OPTIONS" />
|
<entry key="default_options" value="@JVM_OPTIONS" />
|
||||||
|
@ -4,7 +4,7 @@ app.title=Autopsy
|
|||||||
### lowercase version of above
|
### lowercase version of above
|
||||||
app.name=${branding.token}
|
app.name=${branding.token}
|
||||||
### if left unset, version will default to today's date
|
### 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 must be one of: DEVELOPMENT, RELEASE
|
||||||
#build.type=RELEASE
|
#build.type=RELEASE
|
||||||
build.type=DEVELOPMENT
|
build.type=DEVELOPMENT
|
||||||
@ -16,7 +16,7 @@ update_versions=false
|
|||||||
#custom JVM options
|
#custom JVM options
|
||||||
#Note: can be higher on 64 bit systems, should be in sync with build.xml
|
#Note: can be higher on 64 bit systems, should be in sync with build.xml
|
||||||
# for Japanese version add: -J-Duser.language=ja
|
# 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.license-type=apache.v2
|
||||||
auxiliary.org-netbeans-modules-apisupport-installer.os-linux=false
|
auxiliary.org-netbeans-modules-apisupport-installer.os-linux=false
|
||||||
auxiliary.org-netbeans-modules-apisupport-installer.os-macosx=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
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from tskdbdiff import TskDbDiff, TskDbDiffException
|
from tskdbdiff import TskDbDiff, TskDbDiffException, PGSettings
|
||||||
import codecs
|
import codecs
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
@ -132,17 +132,9 @@ class TestRunner(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if isMultiUser:
|
if isMultiUser:
|
||||||
if test_config.output_parent_dir.endswith("single_user"):
|
test_config.testUserCase='multi'
|
||||||
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'
|
|
||||||
else:
|
else:
|
||||||
if test_config.output_parent_dir.endswith("multi_user"):
|
test_config.testUserCase='single'
|
||||||
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._init_logs()
|
test_config._init_logs()
|
||||||
|
|
||||||
@ -191,7 +183,7 @@ class TestRunner(object):
|
|||||||
Errors.print_error("No image had any gold; Regression did not run")
|
Errors.print_error("No image had any gold; Regression did not run")
|
||||||
exit(1)
|
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)
|
html = open(test_config.html_log)
|
||||||
Errors.add_errors_out(html.name)
|
Errors.add_errors_out(html.name)
|
||||||
html.close()
|
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:
|
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.")
|
Errors.print_error("Autopsy test failed. Please check the build log antlog.txt for details.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# exit if .db was not created
|
# 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)):
|
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")
|
Errors.print_error("Autopsy did not run properly; No .db file was created")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
try:
|
try:
|
||||||
# Dump the database before we diff or use it for rebuild
|
# 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),
|
db_file = test_data.get_db_path(DBType.OUTPUT)
|
||||||
test_data.get_sorted_data_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:
|
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)
|
sys.exit(1)
|
||||||
|
|
||||||
# merges logs into a single log for later diff / rebuild
|
# merges logs into a single log for later diff / rebuild
|
||||||
@ -374,7 +367,8 @@ class TestRunner(object):
|
|||||||
|
|
||||||
# Copy files to gold
|
# Copy files to gold
|
||||||
try:
|
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)):
|
if file_exists(test_data.get_sorted_data_path(DBType.OUTPUT)):
|
||||||
shutil.copy(test_data.get_sorted_data_path(DBType.OUTPUT), dataoutpth)
|
shutil.copy(test_data.get_sorted_data_path(DBType.OUTPUT), dataoutpth)
|
||||||
shutil.copy(dbdumpinpth, dbdumpoutpth)
|
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("-Dkeyword_path=" + test_config.keyword_path)
|
||||||
test_data.ant.append("-Dnsrl_path=" + test_config.nsrl_path)
|
test_data.ant.append("-Dnsrl_path=" + test_config.nsrl_path)
|
||||||
test_data.ant.append("-Dgold_path=" + test_config.gold)
|
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))
|
test_data.ant.append("-Dout_path=" + make_local_path(test_data.output_path))
|
||||||
else:
|
else:
|
||||||
test_data.ant.append("-Dout_path=" + test_data.output_path)
|
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("-DsolrPort=" + str(test_config.solrPort))
|
||||||
test_data.ant.append("-DmessageServiceHost=" + test_config.messageServiceHost)
|
test_data.ant.append("-DmessageServiceHost=" + test_config.messageServiceHost)
|
||||||
test_data.ant.append("-DmessageServicePort=" + str(test_config.messageServicePort))
|
test_data.ant.append("-DmessageServicePort=" + str(test_config.messageServicePort))
|
||||||
if test_config.userCaseType == "multi":
|
if test_data.isMultiUser:
|
||||||
test_data.ant.append("-DisMultiUser=true")
|
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.
|
# 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")
|
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("Ingesting Image:\n" + test_data.image_file + "\n")
|
||||||
Errors.print_out("CMD: " + " ".join(test_data.ant))
|
Errors.print_out("CMD: " + " ".join(test_data.ant))
|
||||||
Errors.print_out("Starting test...\n")
|
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")
|
antoutpth = make_local_path(test_data.main_config.output_dir, "antRunOutput.txt")
|
||||||
else:
|
else:
|
||||||
antoutpth = test_data.main_config.output_dir + "\\antRunOutput.txt"
|
antoutpth = test_data.main_config.output_dir + "\\antRunOutput.txt"
|
||||||
@ -572,6 +566,8 @@ class TestData(object):
|
|||||||
self.image_file = str(image)
|
self.image_file = str(image)
|
||||||
self.image = get_image_name(self.image_file)
|
self.image = get_image_name(self.image_file)
|
||||||
self.image_name = self.image
|
self.image_name = self.image
|
||||||
|
# userCaseType
|
||||||
|
self.isMultiUser = True if self.main_config.testUserCase == "multi" else False
|
||||||
# Directory structure and files
|
# Directory structure and files
|
||||||
self.output_path = make_path(self.main_config.output_dir, self.image_name)
|
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")
|
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 +
|
self.test_dbdump = make_path(self.output_path, self.image_name +
|
||||||
"-DBDump.txt")
|
"-DBDump.txt")
|
||||||
self.common_log_path = make_path(self.output_path, self.image_name + "-Exceptions.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_data_dir = make_path(self.main_config.gold, self.image_name)
|
||||||
self.gold_archive = make_path(self.main_config.gold,
|
self.gold_archive = make_path(self.main_config.gold,
|
||||||
self.image_name + "-archive.zip")
|
self.image_name + "-archive.zip")
|
||||||
self.logs_dir = make_path(self.output_path, "logs")
|
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
|
# Results and Info
|
||||||
self.html_report_passed = False
|
self.html_report_passed = False
|
||||||
self.errors_diff_passed = False
|
self.errors_diff_passed = False
|
||||||
@ -611,6 +610,8 @@ class TestData(object):
|
|||||||
self.printout = []
|
self.printout = []
|
||||||
# autopsyPlatform
|
# autopsyPlatform
|
||||||
self.autopsyPlatform = str(self.main_config.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):
|
def ant_to_string(self):
|
||||||
string = ""
|
string = ""
|
||||||
@ -627,7 +628,12 @@ class TestData(object):
|
|||||||
if(db_type == DBType.GOLD):
|
if(db_type == DBType.GOLD):
|
||||||
db_path = make_path(self.gold_data_dir, DB_FILENAME)
|
db_path = make_path(self.gold_data_dir, DB_FILENAME)
|
||||||
elif(db_type == DBType.OUTPUT):
|
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:
|
else:
|
||||||
db_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, BACKUP_DB_FILENAME)
|
db_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, BACKUP_DB_FILENAME)
|
||||||
return db_path
|
return db_path
|
||||||
@ -735,9 +741,11 @@ class TestConfiguration(object):
|
|||||||
self.args = args
|
self.args = args
|
||||||
# Default output parent dir
|
# Default output parent dir
|
||||||
self.output_parent_dir = make_path("..", "output", "results")
|
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.input_dir = make_local_path("..","input")
|
||||||
self.gold = make_path("..", "output", "gold")
|
self.gold = ""
|
||||||
|
self.singleUser_gold = make_path("..", "output", "gold", "single_user")
|
||||||
# Logs:
|
# Logs:
|
||||||
self.csv = ""
|
self.csv = ""
|
||||||
self.global_csv = ""
|
self.global_csv = ""
|
||||||
@ -769,7 +777,11 @@ class TestConfiguration(object):
|
|||||||
self.messageServiceHost = ""
|
self.messageServiceHost = ""
|
||||||
self.messageServicePort = ""
|
self.messageServicePort = ""
|
||||||
self.userCaseType = "Both"
|
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:
|
if not self.args.single:
|
||||||
self._load_config_file(self.args.config_file)
|
self._load_config_file(self.args.config_file)
|
||||||
else:
|
else:
|
||||||
@ -789,21 +801,21 @@ class TestConfiguration(object):
|
|||||||
parsed_config = parse(config_file)
|
parsed_config = parse(config_file)
|
||||||
logres = []
|
logres = []
|
||||||
counts = {}
|
counts = {}
|
||||||
|
if parsed_config.getElementsByTagName("userCaseType"):
|
||||||
|
self.userCaseType = parsed_config.getElementsByTagName("userCaseType")[0].getAttribute("value").encode().decode("utf_8")
|
||||||
if parsed_config.getElementsByTagName("indir"):
|
if parsed_config.getElementsByTagName("indir"):
|
||||||
self.input_dir = parsed_config.getElementsByTagName("indir")[0].getAttribute("value").encode().decode("utf_8")
|
self.input_dir = parsed_config.getElementsByTagName("indir")[0].getAttribute("value").encode().decode("utf_8")
|
||||||
if parsed_config.getElementsByTagName("outdir"):
|
if parsed_config.getElementsByTagName("singleUser_outdir"):
|
||||||
self.output_parent_dir = parsed_config.getElementsByTagName("outdir")[0].getAttribute("value").encode().decode("utf_8")
|
self.singleUser_outdir = parsed_config.getElementsByTagName("singleUser_outdir")[0].getAttribute("value").encode().decode("utf_8")
|
||||||
if parsed_config.getElementsByTagName("global_csv"):
|
if parsed_config.getElementsByTagName("singleUser_golddir"):
|
||||||
self.global_csv = parsed_config.getElementsByTagName("global_csv")[0].getAttribute("value").encode().decode("utf_8")
|
self.singleUser_gold = parsed_config.getElementsByTagName("singleUser_golddir")[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("timing"):
|
if parsed_config.getElementsByTagName("timing"):
|
||||||
self.timing = parsed_config.getElementsByTagName("timing")[0].getAttribute("value").encode().decode("utf_8")
|
self.timing = parsed_config.getElementsByTagName("timing")[0].getAttribute("value").encode().decode("utf_8")
|
||||||
if parsed_config.getElementsByTagName("autopsyPlatform"):
|
if parsed_config.getElementsByTagName("autopsyPlatform"):
|
||||||
self.autopsyPlatform = parsed_config.getElementsByTagName("autopsyPlatform")[0].getAttribute("value").encode().decode("utf_8")
|
self.autopsyPlatform = parsed_config.getElementsByTagName("autopsyPlatform")[0].getAttribute("value").encode().decode("utf_8")
|
||||||
# Multi-user settings
|
# 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"):
|
if parsed_config.getElementsByTagName("dbHost"):
|
||||||
self.dbHost = parsed_config.getElementsByTagName("dbHost")[0].getAttribute("value").encode().decode("utf_8")
|
self.dbHost = parsed_config.getElementsByTagName("dbHost")[0].getAttribute("value").encode().decode("utf_8")
|
||||||
if parsed_config.getElementsByTagName("dbPort"):
|
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")
|
self.messageServiceHost = parsed_config.getElementsByTagName("messageServiceHost")[0].getAttribute("value").encode().decode("utf_8")
|
||||||
if parsed_config.getElementsByTagName("messageServicePort"):
|
if parsed_config.getElementsByTagName("messageServicePort"):
|
||||||
self.messageServicePort = parsed_config.getElementsByTagName("messageServicePort")[0].getAttribute("value").encode().decode("utf_8")
|
self.messageServicePort = parsed_config.getElementsByTagName("messageServicePort")[0].getAttribute("value").encode().decode("utf_8")
|
||||||
if parsed_config.getElementsByTagName("userCaseType"):
|
if parsed_config.getElementsByTagName("multiUser_outdir"):
|
||||||
self.userCaseType = parsed_config.getElementsByTagName("userCaseType")[0].getAttribute("value").encode().decode("utf_8")
|
self.multiUser_outdir = parsed_config.getElementsByTagName("multiUser_outdir")[0].getAttribute("value").encode().decode("utf_8")
|
||||||
self._init_imgs(parsed_config)
|
self._init_imgs(parsed_config)
|
||||||
self._init_build_info(parsed_config)
|
self._init_build_info(parsed_config)
|
||||||
|
|
||||||
@ -831,7 +843,7 @@ class TestConfiguration(object):
|
|||||||
logging.critical(traceback.format_exc())
|
logging.critical(traceback.format_exc())
|
||||||
print(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():
|
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. ")
|
Errors.print_error("Please provide database connection information via configuration file. ")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -841,18 +853,31 @@ class TestConfiguration(object):
|
|||||||
if not self.messageServiceHost.strip() or not self.messageServicePort.strip():
|
if not self.messageServiceHost.strip() or not self.messageServicePort.strip():
|
||||||
Errors.print_error("Please provide ActiveMQ host name and port number via configuration file. ")
|
Errors.print_error("Please provide ActiveMQ host name and port number via configuration file. ")
|
||||||
sys.exit(1)
|
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):
|
def _init_logs(self):
|
||||||
"""Setup output folder, logs, and reporting infrastructure."""
|
"""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):
|
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))
|
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"))
|
self.output_dir = make_path(self.output_parent_dir, time.strftime("%Y.%m.%d-%H.%M.%S"))
|
||||||
|
|
||||||
os.makedirs(self.output_dir)
|
os.makedirs(self.output_dir)
|
||||||
self.csv = make_path(self.output_dir, "CSV.txt")
|
self.csv = make_path(self.output_dir, "CSV.txt")
|
||||||
self.html_log = make_path(self.output_dir, "AutopsyTestCase.html")
|
self.html_log = make_path(self.output_dir, "AutopsyTestCase.html")
|
||||||
log_name = ''
|
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]
|
a = ["cygpath", "-u", self.output_dir]
|
||||||
cygpath_output_dir = subprocess.check_output(a).decode('utf-8')
|
cygpath_output_dir = subprocess.check_output(a).decode('utf-8')
|
||||||
log_name = cygpath_output_dir.rstrip() + "/regression.log"
|
log_name = cygpath_output_dir.rstrip() + "/regression.log"
|
||||||
@ -860,6 +885,22 @@ class TestConfiguration(object):
|
|||||||
log_name = self.output_dir + "\\regression.log"
|
log_name = self.output_dir + "\\regression.log"
|
||||||
logging.basicConfig(filename=log_name, level=logging.DEBUG)
|
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):
|
def _init_build_info(self, parsed_config):
|
||||||
"""Initializes paths that point to information necessary to run the AutopsyIngest."""
|
"""Initializes paths that point to information necessary to run the AutopsyIngest."""
|
||||||
build_elements = parsed_config.getElementsByTagName("build")
|
build_elements = parsed_config.getElementsByTagName("build")
|
||||||
@ -878,22 +919,6 @@ class TestConfiguration(object):
|
|||||||
else:
|
else:
|
||||||
msg = "File: " + value + " doesn't exist"
|
msg = "File: " + value + " doesn't exist"
|
||||||
Errors.print_error(msg)
|
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 #
|
# Functions relating to comparing outputs #
|
||||||
@ -915,7 +940,7 @@ class TestResultsDiffer(object):
|
|||||||
gold_bb_dump = test_data.get_sorted_data_path(DBType.GOLD)
|
gold_bb_dump = test_data.get_sorted_data_path(DBType.GOLD)
|
||||||
gold_dump = test_data.get_db_dump_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,
|
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
|
# Compare Exceptions
|
||||||
# replace is a fucntion that replaces strings of digits with 'd'
|
# 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
|
# 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.
|
# 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)
|
shutil.copy(gold_file, gold_file_in_output_dir)
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@ -1579,7 +1604,10 @@ def copy_logs(test_data):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# copy logs from autopsy case's Log folder
|
# 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)
|
shutil.copytree(log_dir, test_data.logs_dir)
|
||||||
|
|
||||||
# copy logs from userdir0/var/log
|
# copy logs from userdir0/var/log
|
||||||
|
@ -8,6 +8,9 @@ import os
|
|||||||
import codecs
|
import codecs
|
||||||
import datetime
|
import datetime
|
||||||
import sys
|
import sys
|
||||||
|
import psycopg2
|
||||||
|
import psycopg2.extras
|
||||||
|
import socket
|
||||||
|
|
||||||
class TskDbDiff(object):
|
class TskDbDiff(object):
|
||||||
"""Compares two TSK/Autospy SQLite databases.
|
"""Compares two TSK/Autospy SQLite databases.
|
||||||
@ -27,7 +30,7 @@ class TskDbDiff(object):
|
|||||||
autopsy_db_file:
|
autopsy_db_file:
|
||||||
gold_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.
|
"""Constructor for TskDbDiff.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -51,6 +54,12 @@ class TskDbDiff(object):
|
|||||||
self._bb_dump = ""
|
self._bb_dump = ""
|
||||||
self._dump = ""
|
self._dump = ""
|
||||||
self.verbose = verbose
|
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:
|
if self.gold_bb_dump is None:
|
||||||
self._generate_gold_bb_dump = True
|
self._generate_gold_bb_dump = True
|
||||||
@ -68,13 +77,13 @@ class TskDbDiff(object):
|
|||||||
|
|
||||||
# generate the gold database dumps if necessary
|
# generate the gold database dumps if necessary
|
||||||
if self._generate_gold_dump:
|
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:
|
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)
|
# generate the output database dumps (both DB and BB)
|
||||||
TskDbDiff._dump_output_db_nonbb(self.output_db_file, self._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)
|
TskDbDiff._dump_output_db_bb(self.output_db_file, self._bb_dump, self.isMultiUser, self.pgSettings)
|
||||||
|
|
||||||
# Compare non-BB
|
# Compare non-BB
|
||||||
dump_diff_pass = self._diff(self._dump, self.gold_dump, self._dump_diff)
|
dump_diff_pass = self._diff(self._dump, self.gold_dump, self._dump_diff)
|
||||||
@ -163,7 +172,7 @@ class TskDbDiff(object):
|
|||||||
return False
|
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.
|
"""Dumps sorted text results to the given output location.
|
||||||
|
|
||||||
Smart method that deals with a blackboard comparison to avoid issues
|
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")
|
unsorted_dump = TskDbDiff._get_tmp_file("dump_data", ".txt")
|
||||||
conn = sqlite3.connect(db_file)
|
if isMultiUser:
|
||||||
conn.text_factory = lambda x: x.decode("utf-8", "ignore")
|
conn, unused_db = db_connect(db_file, isMultiUser, pgSettings)
|
||||||
conn.row_factory = sqlite3.Row
|
artifact_cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
|
||||||
|
else: # Use Sqlite
|
||||||
artifact_cursor = conn.cursor()
|
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)
|
# 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.
|
# @@@ 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")
|
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:
|
else:
|
||||||
database_log.write(row["name"] + ' <artifact type="' + row["display_name"] + '" > ')
|
database_log.write(row["name"] + ' <artifact type="' + row["display_name"] + '" > ')
|
||||||
|
|
||||||
# Get attributes for this artifact
|
if isMultiUser:
|
||||||
attribute_cursor = conn.cursor()
|
attribute_cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
|
||||||
|
else:
|
||||||
|
attribute_cursor = conn.cursor()
|
||||||
looptry = True
|
looptry = True
|
||||||
artifact_count += 1
|
artifact_count += 1
|
||||||
try:
|
try:
|
||||||
art_id = ""
|
art_id = ""
|
||||||
art_id = str(row["artifact_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()
|
attributes = attribute_cursor.fetchall()
|
||||||
|
|
||||||
# Print attributes
|
# Print attributes
|
||||||
@ -238,13 +257,13 @@ class TskDbDiff(object):
|
|||||||
elif attr["value_type"] == 2:
|
elif attr["value_type"] == 2:
|
||||||
attr_value_as_string = str(attr["value_int64"])
|
attr_value_as_string = str(attr["value_int64"])
|
||||||
elif attr["value_type"] == 3:
|
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:
|
elif attr["value_type"] == 4:
|
||||||
attr_value_as_string = "bytes"
|
attr_value_as_string = "bytes"
|
||||||
elif attr["value_type"] == 5:
|
elif attr["value_type"] == 5:
|
||||||
attr_value_as_string = str(attr["value_int64"])
|
attr_value_as_string = str(attr["value_int64"])
|
||||||
if attr["display_name"] == "Associated Artifact":
|
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]")
|
patrn = re.compile("[\n\0\a\b\r\f]")
|
||||||
attr_value_as_string = re.sub(patrn, ' ', attr_value_as_string)
|
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 + '" />')
|
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)
|
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.
|
"""Dumps a database to a text file.
|
||||||
|
|
||||||
Does not dump the artifact and attributes.
|
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
|
dump_file: a pathto_File, the location to dump the non-blackboard database items
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Make a copy that we can modify
|
conn, backup_db_file = db_connect(db_file, isMultiUser, pgSettings)
|
||||||
backup_db_file = TskDbDiff._get_tmp_file("tsk_backup_db", ".db")
|
id_files_table = build_id_files_table(conn.cursor(), isMultiUser)
|
||||||
shutil.copy(db_file, backup_db_file)
|
id_vs_parts_table = build_id_vs_parts_table(conn.cursor(), isMultiUser)
|
||||||
# We sometimes get situations with messed up permissions
|
id_vs_info_table = build_id_vs_info_table(conn.cursor(), isMultiUser)
|
||||||
os.chmod (backup_db_file, 0o777)
|
id_fs_info_table = build_id_fs_info_table(conn.cursor(), isMultiUser)
|
||||||
|
id_objects_table = build_id_objects_table(conn.cursor(), isMultiUser)
|
||||||
conn = sqlite3.connect(backup_db_file)
|
id_artifact_types_table = build_id_artifact_types_table(conn.cursor(), isMultiUser)
|
||||||
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())
|
|
||||||
id_obj_path_table = build_id_obj_path_table(id_files_table, id_objects_table, id_artifact_types_table)
|
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")
|
#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
|
||||||
# Delete the blackboard tables
|
os.environ['PGPASSWORD']=pgSettings.password
|
||||||
conn.execute("DROP TABLE blackboard_artifacts")
|
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"]
|
||||||
conn.execute("DROP TABLE blackboard_attributes")
|
subprocess.call(pgDump)
|
||||||
|
postgreSQL_db = codecs.open("postgreSQLDump.sql", "r", "utf-8")
|
||||||
# Write to the database dump
|
# Write to the database dump
|
||||||
with codecs.open(dump_file, "wb", "utf_8") as db_log:
|
with codecs.open(dump_file, "wb", "utf_8") as db_log:
|
||||||
for line in conn.iterdump():
|
dump_line = ''
|
||||||
line = normalize_db_entry(line, id_obj_path_table, id_vs_parts_table, id_vs_info_table, id_fs_info_table, id_objects_table)
|
for line in postgreSQL_db:
|
||||||
db_log.write('%s\n' % line)
|
line = line.strip('\r\n ')
|
||||||
# Now sort the file
|
# 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]
|
srtcmdlst = ["sort", dump_file, "-o", dump_file]
|
||||||
subprocess.call(srtcmdlst)
|
subprocess.call(srtcmdlst)
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
# cleanup the backup
|
# 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.
|
"""Dumps the given database to text files for later comparison.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -337,8 +372,8 @@ class TskDbDiff(object):
|
|||||||
dump_file: a pathto_File, the location to dump the non-blackboard database items
|
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
|
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_nonbb(db_file, dump_file, isMultiUser, pgSettings)
|
||||||
TskDbDiff._dump_output_db_bb(db_file, bb_dump_file)
|
TskDbDiff._dump_output_db_bb(db_file, bb_dump_file, isMultiUser, pgSettings)
|
||||||
|
|
||||||
|
|
||||||
def _get_tmp_file(base, ext):
|
def _get_tmp_file(base, ext):
|
||||||
@ -349,6 +384,26 @@ class TskDbDiff(object):
|
|||||||
class TskDbDiffException(Exception):
|
class TskDbDiffException(Exception):
|
||||||
pass
|
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):
|
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.
|
""" 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_table: a map from object ids to file paths.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
files_index = line.find('INSERT INTO "tsk_files"')
|
# Sqlite statement use double quotes for table name, PostgreSQL doesn't. We check both databases results for normalization.
|
||||||
path_index = line.find('INSERT INTO "tsk_files_path"')
|
files_index = line.find('INSERT INTO "tsk_files"') > -1 or line.find('INSERT INTO tsk_files ') > -1
|
||||||
object_index = line.find('INSERT INTO "tsk_objects"')
|
path_index = line.find('INSERT INTO "tsk_files_path"') > -1 or line.find('INSERT INTO tsk_files_path ') > -1
|
||||||
report_index = line.find('INSERT INTO "reports"')
|
object_index = line.find('INSERT INTO "tsk_objects"') > -1 or line.find('INSERT INTO tsk_objects ') > -1
|
||||||
layout_index = line.find('INSERT INTO "tsk_file_layout"')
|
report_index = line.find('INSERT INTO "reports"') > -1 or line.find('INSERT INTO reports ') > -1
|
||||||
data_source_info_index = line.find('INSERT INTO "data_source_info"')
|
layout_index = line.find('INSERT INTO "tsk_file_layout"') > -1 or line.find('INSERT INTO tsk_file_layout ') > -1
|
||||||
ingest_job_index = line.find('INSERT INTO "ingest_jobs"')
|
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(')')]
|
parens = line[line.find('(') + 1 : line.rfind(')')]
|
||||||
fields_list = parens.replace(" ", "").split(',')
|
fields_list = parens.replace(" ", "").split(',')
|
||||||
|
|
||||||
# remove object ID
|
# remove object ID
|
||||||
if (files_index != -1):
|
if files_index:
|
||||||
obj_id = fields_list[0]
|
|
||||||
path = files_table[int(obj_id)]
|
|
||||||
newLine = ('INSERT INTO "tsk_files" VALUES(' + ', '.join(fields_list[1:]) + ');')
|
newLine = ('INSERT INTO "tsk_files" VALUES(' + ', '.join(fields_list[1:]) + ');')
|
||||||
return newLine
|
return newLine
|
||||||
# remove object ID
|
# remove object ID
|
||||||
elif (path_index != -1):
|
elif path_index:
|
||||||
obj_id = int(fields_list[0])
|
obj_id = int(fields_list[0])
|
||||||
objValue = files_table[obj_id]
|
objValue = files_table[obj_id]
|
||||||
# remove the obj_id from ModuleOutput/EmbeddedFileExtractor directory
|
# 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:]
|
pathValue = fields_list[1][:idx_pre+1] + dir_to_replace + fields_list[1][idx_pos:]
|
||||||
else:
|
else:
|
||||||
pathValue = fields_list[1]
|
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:]) + ');')
|
newLine = ('INSERT INTO "tsk_files_path" VALUES(' + objValue + ', ' + pathValue + ', ' + ', '.join(fields_list[2:]) + ');')
|
||||||
return newLine
|
return newLine
|
||||||
# remove object ID
|
# remove object ID
|
||||||
elif (layout_index != -1):
|
elif layout_index:
|
||||||
obj_id = fields_list[0]
|
obj_id = fields_list[0]
|
||||||
path= files_table[int(obj_id)]
|
path= files_table[int(obj_id)]
|
||||||
newLine = ('INSERT INTO "tsk_file_layout" VALUES(' + path + ', ' + ', '.join(fields_list[1:]) + ');')
|
newLine = ('INSERT INTO "tsk_file_layout" VALUES(' + path + ', ' + ', '.join(fields_list[1:]) + ');')
|
||||||
return newLine
|
return newLine
|
||||||
# remove object ID
|
# remove object ID
|
||||||
elif (object_index != -1):
|
elif object_index:
|
||||||
obj_id = fields_list[0]
|
obj_id = fields_list[0]
|
||||||
parent_id = fields_list[1]
|
parent_id = fields_list[1]
|
||||||
newLine = 'INSERT INTO "tsk_objects" VALUES('
|
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:
|
else:
|
||||||
return line
|
return line
|
||||||
# remove time-based information, ie Test_6/11/14 -> Test
|
# remove time-based information, ie Test_6/11/14 -> Test
|
||||||
elif (report_index != -1):
|
elif report_index:
|
||||||
fields_list[1] = "AutopsyTestCase"
|
fields_list[1] = "AutopsyTestCase"
|
||||||
fields_list[2] = "0"
|
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
|
return newLine
|
||||||
elif (data_source_info_index != -1):
|
elif data_source_info_index:
|
||||||
fields_list[1] = "{device id}"
|
fields_list[1] = "{device id}"
|
||||||
newLine = ('INSERT INTO "data_source_info" VALUES(' + ','.join(fields_list) + ');')
|
newLine = ('INSERT INTO "data_source_info" VALUES(' + ','.join(fields_list) + ');')
|
||||||
return newLine
|
return newLine
|
||||||
elif (ingest_job_index != -1):
|
elif ingest_job_index:
|
||||||
fields_list[2] = "{host_name}"
|
fields_list[2] = "{host_name}"
|
||||||
start_time = int(fields_list[3])
|
start_time = int(fields_list[3])
|
||||||
end_time = int(fields_list[4])
|
end_time = int(fields_list[4])
|
||||||
if (start_time <= end_time):
|
if (start_time <= end_time):
|
||||||
fields_list[3] = "0"
|
fields_list[3] = "0"
|
||||||
fields_list[4] = "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
|
return newLine
|
||||||
else:
|
else:
|
||||||
return line
|
return line
|
||||||
|
|
||||||
def getAssociatedArtifactType(db_file, artifact_id):
|
def getAssociatedArtifactType(cur, artifact_id, isMultiUser):
|
||||||
# Make a copy that we can modify
|
if isMultiUser:
|
||||||
backup_db_file = TskDbDiff._get_tmp_file("tsk_backup_db", ".db")
|
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])
|
||||||
shutil.copy(db_file, backup_db_file)
|
else:
|
||||||
# We sometimes get situations with messed up permissions
|
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])
|
||||||
os.chmod (backup_db_file, 0o777)
|
|
||||||
|
|
||||||
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()
|
info = cur.fetchone()
|
||||||
|
|
||||||
conn.close()
|
|
||||||
# cleanup the backup
|
|
||||||
os.remove(backup_db_file)
|
|
||||||
|
|
||||||
return "File path: " + info[0] + " Artifact Type: " + info[1]
|
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.
|
"""Build the map of object ids to file paths.
|
||||||
|
|
||||||
Args:
|
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
|
# 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
|
# 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
|
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.
|
"""Build the map of object ids to vs_parts.
|
||||||
|
|
||||||
Args:
|
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
|
# 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
|
# 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
|
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.
|
"""Build the map of object ids to vs_info.
|
||||||
|
|
||||||
Args:
|
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
|
# 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
|
# 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
|
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.
|
"""Build the map of object ids to fs_info.
|
||||||
|
|
||||||
Args:
|
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
|
# 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
|
# 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
|
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.
|
"""Build the map of object ids to par_id.
|
||||||
|
|
||||||
Args:
|
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
|
# 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
|
# 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
|
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.
|
"""Build the map of object ids to artifact ids.
|
||||||
|
|
||||||
Args:
|
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
|
# 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
|
# 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
|
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]]
|
mapping[k] = path + "/" + artifacts_table[v[0]]
|
||||||
return mapping
|
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():
|
def main():
|
||||||
try:
|
try:
|
||||||
sys.argv.pop(0)
|
sys.argv.pop(0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user