resolved merge conflicts.

This commit is contained in:
Nick Davis 2017-06-28 13:11:35 -04:00
commit 6b2316e2b8
18 changed files with 373 additions and 210 deletions

View File

@ -24,6 +24,7 @@ import javax.swing.JLabel;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer; import javax.swing.table.TableCellRenderer;
import org.sleuthkit.datamodel.TskData;
/** /**
* Renderer for cells in data content viewer table * Renderer for cells in data content viewer table
@ -49,19 +50,15 @@ public class DataContentViewerOtherCasesTableCellRenderer implements TableCellRe
background = Color.BLUE; background = Color.BLUE;
} else { } else {
String known_status = (String) table.getModel().getValueAt(row, 5); String known_status = (String) table.getModel().getValueAt(row, 5);
switch (known_status) { if (known_status.equals(TskData.FileKnown.BAD.getName())) {
case "Bad":
foreground = Color.WHITE; foreground = Color.WHITE;
background = Color.RED; background = Color.RED;
break; } else if (known_status.equals(TskData.FileKnown.UNKNOWN.getName())) {
case "Unknown":
foreground = Color.BLACK; foreground = Color.BLACK;
background = Color.YELLOW; background = Color.YELLOW;
break; } else {
default:
foreground = Color.BLACK; foreground = Color.BLACK;
background = Color.WHITE; background = Color.WHITE;
break;
} }
} }
renderer.setForeground(foreground); renderer.setForeground(foreground);

View File

@ -48,7 +48,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
DEVICE(Bundle.DataContentViewerOtherCasesTableModel_device(), 145), DEVICE(Bundle.DataContentViewerOtherCasesTableModel_device(), 145),
TYPE(Bundle.DataContentViewerOtherCasesTableModel_type(), 40), TYPE(Bundle.DataContentViewerOtherCasesTableModel_type(), 40),
VALUE(Bundle.DataContentViewerOtherCasesTableModel_value(), 145), VALUE(Bundle.DataContentViewerOtherCasesTableModel_value(), 145),
KNOWN(Bundle.DataContentViewerOtherCasesTableModel_known(), 25), KNOWN(Bundle.DataContentViewerOtherCasesTableModel_known(), 45),
SCOPE(Bundle.DataContentViewerOtherCasesTableModel_scope(), 20), SCOPE(Bundle.DataContentViewerOtherCasesTableModel_scope(), 20),
COMMENT(Bundle.DataContentViewerOtherCasesTableModel_comment(), 200), COMMENT(Bundle.DataContentViewerOtherCasesTableModel_comment(), 200),
FILE_PATH(Bundle.DataContentViewerOtherCasesTableModel_path(), 250); FILE_PATH(Bundle.DataContentViewerOtherCasesTableModel_path(), 250);
@ -160,7 +160,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel {
value = eamArtifactInstance.getGlobalStatus().toString(); value = eamArtifactInstance.getGlobalStatus().toString();
break; break;
case KNOWN: case KNOWN:
value = eamArtifactInstance.getKnownStatus().toString(); value = eamArtifactInstance.getKnownStatus().getName();
break; break;
case COMMENT: case COMMENT:
value = eamArtifactInstance.getComment(); value = eamArtifactInstance.getComment();

View File

@ -35,6 +35,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TskData;
/** /**
* *
@ -100,7 +101,6 @@ public abstract class AbstractSqlEamDb implements EamDb {
// } // }
// // else, schema is current // // else, schema is current
// } // }
/** /**
* Setup and create a connection to the selected database implementation * Setup and create a connection to the selected database implementation
*/ */
@ -550,8 +550,8 @@ public abstract class AbstractSqlEamDb implements EamDb {
} }
/** /**
* Retrieves eamArtifact instances from the database that are associated with * Retrieves eamArtifact instances from the database that are associated
* the eamArtifactType and eamArtifactValue of the given eamArtifact. * with the eamArtifactType and eamArtifactValue of the given eamArtifact.
* *
* @param eamArtifact The type/value to look up (artifact with 0 instances) * @param eamArtifact The type/value to look up (artifact with 0 instances)
* *
@ -599,8 +599,8 @@ public abstract class AbstractSqlEamDb implements EamDb {
} }
/** /**
* Retrieves eamArtifact instances from the database that are associated with * Retrieves eamArtifact instances from the database that are associated
* the aType and filePath * with the aType and filePath
* *
* @param aType EamArtifact.Type to search for * @param aType EamArtifact.Type to search for
* @param filePath File path to search for * @param filePath File path to search for
@ -874,6 +874,13 @@ public abstract class AbstractSqlEamDb implements EamDb {
} }
} }
/**
* Get the conflict clause for bulk update statements
*
* @return The conflict clause for bulk update statements
*/
protected abstract String getConflictClause();
/** /**
* Executes a bulk insert of the eamArtifacts added from the * Executes a bulk insert of the eamArtifacts added from the
* prepareBulkArtifact() method * prepareBulkArtifact() method
@ -899,7 +906,8 @@ public abstract class AbstractSqlEamDb implements EamDb {
sql.append(tableName); sql.append(tableName);
sql.append(" (case_id, data_source_id, value, file_path, known_status, comment) "); sql.append(" (case_id, data_source_id, value, file_path, known_status, comment) ");
sql.append("VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "); sql.append("VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), ");
sql.append("(SELECT id FROM data_sources WHERE device_id=? LIMIT 1), ?, ?, ?, ?)"); sql.append("(SELECT id FROM data_sources WHERE device_id=? LIMIT 1), ?, ?, ?, ?) ");
sql.append(getConflictClause());
bulkPs = conn.prepareStatement(sql.toString()); bulkPs = conn.prepareStatement(sql.toString());
@ -949,7 +957,8 @@ public abstract class AbstractSqlEamDb implements EamDb {
try { try {
String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, " String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
+ "examiner_name, examiner_email, examiner_phone, notes) " + "examiner_name, examiner_email, examiner_phone, notes) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
+ getConflictClause();
bulkPs = conn.prepareStatement(sql); bulkPs = conn.prepareStatement(sql);
for (EamCase eamCase : cases) { for (EamCase eamCase : cases) {
@ -987,8 +996,8 @@ public abstract class AbstractSqlEamDb implements EamDb {
} }
/** /**
* Sets an eamArtifact instance as knownStatus = "Bad". If eamArtifact exists, * Sets an eamArtifact instance as knownStatus = "Bad". If eamArtifact
* it is updated. If eamArtifact does not exist nothing happens * exists, it is updated. If eamArtifact does not exist nothing happens
* *
* @param eamArtifact Artifact containing exactly one (1) ArtifactInstance. * @param eamArtifact Artifact containing exactly one (1) ArtifactInstance.
*/ */
@ -1034,13 +1043,13 @@ public abstract class AbstractSqlEamDb implements EamDb {
int instance_id = resultSet.getInt("id"); int instance_id = resultSet.getInt("id");
preparedUpdate = conn.prepareStatement(sqlUpdate.toString()); preparedUpdate = conn.prepareStatement(sqlUpdate.toString());
preparedUpdate.setString(1, EamArtifactInstance.KnownStatus.BAD.name()); preparedUpdate.setString(1, TskData.FileKnown.BAD.name());
preparedUpdate.setString(2, eamInstance.getComment()); preparedUpdate.setString(2, eamInstance.getComment());
preparedUpdate.setInt(3, instance_id); preparedUpdate.setInt(3, instance_id);
preparedUpdate.executeUpdate(); preparedUpdate.executeUpdate();
} else { } else {
eamArtifact.getInstances().get(0).setKnownStatus(EamArtifactInstance.KnownStatus.BAD); eamArtifact.getInstances().get(0).setKnownStatus(TskData.FileKnown.BAD);
addArtifact(eamArtifact); addArtifact(eamArtifact);
} }
@ -1055,7 +1064,8 @@ public abstract class AbstractSqlEamDb implements EamDb {
} }
/** /**
* Gets list of matching eamArtifact instances that have knownStatus = "Bad". * Gets list of matching eamArtifact instances that have knownStatus =
* "Bad".
* *
* @param eamArtifact Artifact containing Type and Value * @param eamArtifact Artifact containing Type and Value
* *
@ -1086,7 +1096,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
try { try {
preparedStatement = conn.prepareStatement(sql.toString()); preparedStatement = conn.prepareStatement(sql.toString());
preparedStatement.setString(1, eamArtifact.getArtifactValue()); preparedStatement.setString(1, eamArtifact.getArtifactValue());
preparedStatement.setString(2, EamArtifactInstance.KnownStatus.BAD.name()); preparedStatement.setString(2, TskData.FileKnown.BAD.name());
resultSet = preparedStatement.executeQuery(); resultSet = preparedStatement.executeQuery();
while (resultSet.next()) { while (resultSet.next()) {
artifactInstance = getEamArtifactInstanceFromResultSet(resultSet); artifactInstance = getEamArtifactInstanceFromResultSet(resultSet);
@ -1127,7 +1137,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
try { try {
preparedStatement = conn.prepareStatement(sql.toString()); preparedStatement = conn.prepareStatement(sql.toString());
preparedStatement.setString(1, eamArtifact.getArtifactValue()); preparedStatement.setString(1, eamArtifact.getArtifactValue());
preparedStatement.setString(2, EamArtifactInstance.KnownStatus.BAD.name()); preparedStatement.setString(2, TskData.FileKnown.BAD.name());
resultSet = preparedStatement.executeQuery(); resultSet = preparedStatement.executeQuery();
resultSet.next(); resultSet.next();
badInstances = resultSet.getLong(1); badInstances = resultSet.getLong(1);
@ -1177,7 +1187,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
try { try {
preparedStatement = conn.prepareStatement(sql.toString()); preparedStatement = conn.prepareStatement(sql.toString());
preparedStatement.setString(1, eamArtifact.getArtifactValue()); preparedStatement.setString(1, eamArtifact.getArtifactValue());
preparedStatement.setString(2, EamArtifactInstance.KnownStatus.BAD.name()); preparedStatement.setString(2, TskData.FileKnown.BAD.name());
resultSet = preparedStatement.executeQuery(); resultSet = preparedStatement.executeQuery();
while (resultSet.next()) { while (resultSet.next()) {
caseNames.add(resultSet.getString("case_name")); caseNames.add(resultSet.getString("case_name"));
@ -1218,7 +1228,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
try { try {
preparedStatement = conn.prepareStatement(sql); preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1, eamArtifact.getArtifactValue()); preparedStatement.setString(1, eamArtifact.getArtifactValue());
preparedStatement.setString(2, EamArtifactInstance.KnownStatus.BAD.name()); preparedStatement.setString(2, TskData.FileKnown.BAD.name());
resultSet = preparedStatement.executeQuery(); resultSet = preparedStatement.executeQuery();
resultSet.next(); resultSet.next();
badInstances = resultSet.getLong(1); badInstances = resultSet.getLong(1);
@ -1440,24 +1450,6 @@ public abstract class AbstractSqlEamDb implements EamDb {
} }
} }
/**
* Add a new global file instance to the bulk collection
*
* @param eamGlobalFileInstance The global file instance to add
* @throws EamDbException
*/
// @Override
// public void prepareGlobalFileInstance(EamGlobalFileInstance eamGlobalFileInstance) throws EamDbException {
// synchronized (bulkGlobalArtifacts) {
// bulkGlobalArtifacts.get("FILES").add(eamGlobalFileInstance); // NON-NLS
// bulkGlobalArtifactsCount++;
//
// if (bulkGlobalArtifactsCount >= bulkArtifactsThreshold) {
// bulkInsertGlobalFileInstances();
// }
// }
// }
/** /**
* Insert the bulk collection of Global File Instances * Insert the bulk collection of Global File Instances
* *
@ -1470,7 +1462,8 @@ public abstract class AbstractSqlEamDb implements EamDb {
PreparedStatement bulkPs = null; PreparedStatement bulkPs = null;
try { try {
// FUTURE: have a separate global_files table for each Type. // FUTURE: have a separate global_files table for each Type.
String sql = "INSERT INTO global_files(global_reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?)"; String sql = "INSERT INTO global_files(global_reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
+ getConflictClause();
bulkPs = conn.prepareStatement(sql); bulkPs = conn.prepareStatement(sql);
@ -1495,7 +1488,9 @@ public abstract class AbstractSqlEamDb implements EamDb {
* Get all global file instances having a given MD5 hash * Get all global file instances having a given MD5 hash
* *
* @param MD5Hash The hash to lookup * @param MD5Hash The hash to lookup
*
* @return List of all global file instances with a given hash * @return List of all global file instances with a given hash
*
* @throws EamDbException * @throws EamDbException
*/ */
@Override @Override
@ -1529,6 +1524,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
* Add a new EamArtifact.Type to the db. * Add a new EamArtifact.Type to the db.
* *
* @param newType New type to add. * @param newType New type to add.
*
* @throws EamDbException * @throws EamDbException
*/ */
@Override @Override
@ -1561,6 +1557,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
* *
* @return List of EamArtifact.Type's. If none are defined in the database, * @return List of EamArtifact.Type's. If none are defined in the database,
* the default list will be returned. * the default list will be returned.
*
* @throws EamDbException * @throws EamDbException
*/ */
@Override @Override
@ -1595,6 +1592,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
* *
* @return List of enabled EamArtifact.Type's. If none are defined in the * @return List of enabled EamArtifact.Type's. If none are defined in the
* database, the default list will be returned. * database, the default list will be returned.
*
* @throws EamDbException * @throws EamDbException
*/ */
@Override @Override
@ -1629,6 +1627,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
* *
* @return List of supported EamArtifact.Type's. If none are defined in the * @return List of supported EamArtifact.Type's. If none are defined in the
* database, the default list will be returned. * database, the default list will be returned.
*
* @throws EamDbException * @throws EamDbException
*/ */
@Override @Override
@ -1661,6 +1660,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
* Update a EamArtifact.Type. * Update a EamArtifact.Type.
* *
* @param aType EamArtifact.Type to update. * @param aType EamArtifact.Type to update.
*
* @throws EamDbException * @throws EamDbException
*/ */
@Override @Override
@ -1693,6 +1693,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
* @param typeName Name of Type to get * @param typeName Name of Type to get
* *
* @return EamArtifact.Type or null if it doesn't exist. * @return EamArtifact.Type or null if it doesn't exist.
*
* @throws EamDbException * @throws EamDbException
*/ */
@Override @Override
@ -1810,7 +1811,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
new EamDataSource(resultSet.getString("device_id"), resultSet.getString("name")), new EamDataSource(resultSet.getString("device_id"), resultSet.getString("name")),
resultSet.getString("file_path"), resultSet.getString("file_path"),
resultSet.getString("comment"), resultSet.getString("comment"),
EamArtifactInstance.KnownStatus.valueOf(resultSet.getString("known_status")), TskData.FileKnown.valueOf(resultSet.getString("known_status")),
EamArtifactInstance.GlobalStatus.LOCAL EamArtifactInstance.GlobalStatus.LOCAL
); );
@ -1858,7 +1859,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
resultSet.getInt("id"), resultSet.getInt("id"),
resultSet.getInt("global_reference_set_id"), resultSet.getInt("global_reference_set_id"),
resultSet.getString("value"), resultSet.getString("value"),
EamArtifactInstance.KnownStatus.valueOf(resultSet.getString("known_status")), TskData.FileKnown.valueOf(resultSet.getString("known_status")),
resultSet.getString("comment") resultSet.getString("comment")
); );

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.io.Serializable; import java.io.Serializable;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.TskData;
/** /**
* *
@ -49,22 +50,22 @@ public class EamArtifactInstance implements Serializable {
} }
} }
public enum KnownStatus { // public enum FileKnown {
UNKNOWN(Bundle.EamArtifactInstances_knownStatus_unknown()), // UNKNOWN(Bundle.EamArtifactInstances_knownStatus_unknown()),
KNOWN(Bundle.EamArtifactInstances_knownStatus_known()), // KNOWN(Bundle.EamArtifactInstances_knownStatus_known()),
BAD(Bundle.EamArtifactInstances_knownStatus_bad()); // BAD(Bundle.EamArtifactInstances_knownStatus_bad());
//
private final String knownStatus; // private final String knownStatus;
//
private KnownStatus(String knownStatus) { // private FileKnown(String knownStatus) {
this.knownStatus = knownStatus; // this.knownStatus = knownStatus;
} // }
//
@Override // @Override
public String toString() { // public String toString() {
return knownStatus; // return knownStatus;
} // }
} // }
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -73,14 +74,14 @@ public class EamArtifactInstance implements Serializable {
private EamDataSource eamDataSource; private EamDataSource eamDataSource;
private String filePath; private String filePath;
private String comment; private String comment;
private KnownStatus knownStatus; private TskData.FileKnown knownStatus;
private GlobalStatus globalStatus; private GlobalStatus globalStatus;
public EamArtifactInstance( public EamArtifactInstance(
EamCase eamCase, EamCase eamCase,
EamDataSource eamDataSource EamDataSource eamDataSource
) { ) {
this("", eamCase, eamDataSource, "", "", KnownStatus.UNKNOWN, GlobalStatus.LOCAL); this("", eamCase, eamDataSource, "", "", TskData.FileKnown.UNKNOWN, GlobalStatus.LOCAL);
} }
public EamArtifactInstance( public EamArtifactInstance(
@ -88,7 +89,7 @@ public class EamArtifactInstance implements Serializable {
EamDataSource eamDataSource, EamDataSource eamDataSource,
String filePath String filePath
) { ) {
this("", eamCase, eamDataSource, filePath, "", KnownStatus.UNKNOWN, GlobalStatus.LOCAL); this("", eamCase, eamDataSource, filePath, "", TskData.FileKnown.UNKNOWN, GlobalStatus.LOCAL);
} }
public EamArtifactInstance( public EamArtifactInstance(
@ -97,7 +98,7 @@ public class EamArtifactInstance implements Serializable {
String filePath, String filePath,
String comment String comment
) { ) {
this("", eamCase, eamDataSource, filePath, comment, KnownStatus.UNKNOWN, GlobalStatus.LOCAL); this("", eamCase, eamDataSource, filePath, comment, TskData.FileKnown.UNKNOWN, GlobalStatus.LOCAL);
} }
public EamArtifactInstance( public EamArtifactInstance(
@ -105,7 +106,7 @@ public class EamArtifactInstance implements Serializable {
EamDataSource eamDataSource, EamDataSource eamDataSource,
String filePath, String filePath,
String comment, String comment,
KnownStatus knownStatus, TskData.FileKnown knownStatus,
GlobalStatus globalStatus GlobalStatus globalStatus
) { ) {
this("", eamCase, eamDataSource, filePath, comment, knownStatus, globalStatus); this("", eamCase, eamDataSource, filePath, comment, knownStatus, globalStatus);
@ -117,7 +118,7 @@ public class EamArtifactInstance implements Serializable {
EamDataSource eamDataSource, EamDataSource eamDataSource,
String filePath, String filePath,
String comment, String comment,
KnownStatus knownStatus, TskData.FileKnown knownStatus,
GlobalStatus globalStatus GlobalStatus globalStatus
) { ) {
this.ID = ID; this.ID = ID;
@ -223,14 +224,14 @@ public class EamArtifactInstance implements Serializable {
/** /**
* @return the knownStatus * @return the knownStatus
*/ */
public KnownStatus getKnownStatus() { public TskData.FileKnown getKnownStatus() {
return knownStatus; return knownStatus;
} }
/** /**
* @param knownStatus the knownStatus to set * @param knownStatus the knownStatus to set
*/ */
public void setKnownStatus(KnownStatus knownStatus) { public void setKnownStatus(TskData.FileKnown knownStatus) {
this.knownStatus = knownStatus; this.knownStatus = knownStatus;
} }

View File

@ -27,6 +27,7 @@ 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.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskDataException;
/** /**
@ -88,7 +89,7 @@ public class EamArtifactUtil {
new EamDataSource(deviceId, af.getDataSource().getName()), new EamDataSource(deviceId, af.getDataSource().getName()),
af.getParentPath() + af.getName(), af.getParentPath() + af.getName(),
"", "",
EamArtifactInstance.KnownStatus.UNKNOWN, TskData.FileKnown.UNKNOWN,
EamArtifactInstance.GlobalStatus.LOCAL EamArtifactInstance.GlobalStatus.LOCAL
); );
eamArtifact.addInstance(eamInstance); eamArtifact.addInstance(eamInstance);

View File

@ -19,7 +19,7 @@
package org.sleuthkit.autopsy.centralrepository.datamodel; package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.util.Objects; import java.util.Objects;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactInstance.KnownStatus; import org.sleuthkit.datamodel.TskData;
/** /**
* Global file hash instance * Global file hash instance
@ -29,14 +29,14 @@ public class EamGlobalFileInstance {
private int instanceID; private int instanceID;
private int globalSetID; private int globalSetID;
private String MD5Hash; private String MD5Hash;
private KnownStatus knownStatus; private TskData.FileKnown knownStatus;
private String comment; private String comment;
public EamGlobalFileInstance( public EamGlobalFileInstance(
int instanceID, int instanceID,
int globalSetID, int globalSetID,
String MD5Hash, String MD5Hash,
KnownStatus knownStatus, TskData.FileKnown knownStatus,
String comment) { String comment) {
this.instanceID = instanceID; this.instanceID = instanceID;
this.globalSetID = globalSetID; this.globalSetID = globalSetID;
@ -48,7 +48,7 @@ public class EamGlobalFileInstance {
public EamGlobalFileInstance( public EamGlobalFileInstance(
int globalSetID, int globalSetID,
String MD5Hash, String MD5Hash,
KnownStatus knownStatus, TskData.FileKnown knownStatus,
String comment) { String comment) {
this(-1, globalSetID, MD5Hash, knownStatus, comment); this(-1, globalSetID, MD5Hash, knownStatus, comment);
} }
@ -69,7 +69,7 @@ public class EamGlobalFileInstance {
int hash = 5; int hash = 5;
hash = 59 * hash + this.globalSetID; hash = 59 * hash + this.globalSetID;
hash = 59 * hash + Objects.hashCode(this.MD5Hash); hash = 59 * hash + Objects.hashCode(this.MD5Hash);
hash = 59 * hash + Objects.hashCode(this.knownStatus); hash = 59 * hash + this.knownStatus.hashCode();
return hash; return hash;
} }
/** /**
@ -117,14 +117,14 @@ public class EamGlobalFileInstance {
/** /**
* @return the knownStatus * @return the knownStatus
*/ */
public KnownStatus getKnownStatus() { public TskData.FileKnown getKnownStatus() {
return knownStatus; return knownStatus;
} }
/** /**
* @param knownStatus the knownStatus to set * @param knownStatus the knownStatus to set
*/ */
public void setKnownStatus(KnownStatus knownStatus) { public void setKnownStatus(TskData.FileKnown knownStatus) {
this.knownStatus = knownStatus; this.knownStatus = knownStatus;
} }

View File

@ -33,6 +33,8 @@ public class PostgresEamDb extends AbstractSqlEamDb {
private final static Logger LOGGER = Logger.getLogger(PostgresEamDb.class.getName()); private final static Logger LOGGER = Logger.getLogger(PostgresEamDb.class.getName());
private final static String CONFLICT_CLAUSE = "ON CONFLICT DO NOTHING";
private static PostgresEamDb instance; private static PostgresEamDb instance;
private static final int CONN_POOL_SIZE = 10; private static final int CONN_POOL_SIZE = 10;
@ -162,6 +164,11 @@ public class PostgresEamDb extends AbstractSqlEamDb {
} }
} }
@Override
protected String getConflictClause() {
return CONFLICT_CLAUSE;
}
@Override @Override
public List<String> getBadTags() { public List<String> getBadTags() {
return dbSettings.getBadTags(); return dbSettings.getBadTags();

View File

@ -36,8 +36,7 @@ import org.sleuthkit.autopsy.coreutils.TextConverter;
import org.sleuthkit.autopsy.coreutils.TextConverterException; import org.sleuthkit.autopsy.coreutils.TextConverterException;
/** /**
* Settings for the Postgres implementation of the Central Repository * Settings for the Postgres implementation of the Central Repository database
* database
*/ */
public final class PostgresEamDbSettings { public final class PostgresEamDbSettings {
@ -167,7 +166,8 @@ public final class PostgresEamDbSettings {
} }
/** /**
* Use the current settings to get an ephemeral client connection for testing. * Use the current settings to get an ephemeral client connection for
* testing.
* *
* @return Connection or null. * @return Connection or null.
*/ */
@ -191,8 +191,8 @@ public final class PostgresEamDbSettings {
} }
/** /**
* 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.
*/ */
@ -240,8 +240,8 @@ public final class PostgresEamDbSettings {
} }
/** /**
* 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.
*/ */
@ -277,6 +277,7 @@ public final class PostgresEamDbSettings {
return true; return true;
} }
/** /**
* Initialize the database schema. * Initialize the database schema.
* *
@ -305,7 +306,6 @@ public final class PostgresEamDbSettings {
// 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 SERIAL PRIMARY KEY,"); createCasesTable.append("id SERIAL PRIMARY KEY,");
@ -402,7 +402,6 @@ public final class PostgresEamDbSettings {
// 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(false); conn = getEphemeralConnection(false);
@ -514,8 +513,8 @@ public final class PostgresEamDbSettings {
} }
/** /**
* To prevent issues where one command can honor case and another cannot, * To prevent issues where one command can honor case and another cannot, we
* we will force the dbname to lower case. * will force the dbname to lower case.
* *
* @return the dbName * @return the dbName
*/ */

View File

@ -25,7 +25,6 @@ import java.sql.Statement;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
/** /**
@ -162,6 +161,12 @@ public class SqliteEamDb extends AbstractSqlEamDb {
} }
} }
@Override
protected String getConflictClause() {
// For sqlite, our conflict clause is part of the table schema
return "";
}
@Override @Override
public List<String> getBadTags() { public List<String> getBadTags() {
return dbSettings.getBadTags(); return dbSettings.getBadTags();

View File

@ -256,8 +256,8 @@ public final class SqliteEamDbSettings {
createCasesTable.append("examiner_email text NOT NULL,"); createCasesTable.append("examiner_email text NOT NULL,");
createCasesTable.append("examiner_phone text NOT NULL,"); createCasesTable.append("examiner_phone text NOT NULL,");
createCasesTable.append("notes text NOT NULL,"); createCasesTable.append("notes text NOT NULL,");
createCasesTable.append("foreign key (org_id) references organizations(id) on update set null on delete set null,"); createCasesTable.append("CONSTRAINT case_uid_unique UNIQUE(case_uid) ON CONFLICT IGNORE,");
createCasesTable.append("CONSTRAINT case_uid_unique UNIQUE(case_uid)"); createCasesTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL");
createCasesTable.append(")"); createCasesTable.append(")");
// NOTE: when there are few cases in the cases table, these indices may not be worthwhile // NOTE: when there are few cases in the cases table, these indices may not be worthwhile
@ -281,7 +281,7 @@ public final class SqliteEamDbSettings {
createGlobalReferenceSetsTable.append("set_name text NOT NULL,"); createGlobalReferenceSetsTable.append("set_name text NOT NULL,");
createGlobalReferenceSetsTable.append("version text NOT NULL,"); createGlobalReferenceSetsTable.append("version text NOT NULL,");
createGlobalReferenceSetsTable.append("import_date text NOT NULL,"); createGlobalReferenceSetsTable.append("import_date text NOT NULL,");
createGlobalReferenceSetsTable.append("foreign key (org_id) references organizations(id) on update set null on delete set null"); createGlobalReferenceSetsTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL");
createGlobalReferenceSetsTable.append(")"); createGlobalReferenceSetsTable.append(")");
String globalReferenceSetsIdx1 = "CREATE INDEX IF NOT EXISTS global_reference_sets_org_id ON global_reference_sets (org_id)"; String globalReferenceSetsIdx1 = "CREATE INDEX IF NOT EXISTS global_reference_sets_org_id ON global_reference_sets (org_id)";
@ -293,8 +293,8 @@ public final class SqliteEamDbSettings {
createGlobalFilesTable.append("value text NOT NULL,"); createGlobalFilesTable.append("value text NOT NULL,");
createGlobalFilesTable.append("known_status text NOT NULL,"); createGlobalFilesTable.append("known_status text NOT NULL,");
createGlobalFilesTable.append("comment text NOT NULL,"); createGlobalFilesTable.append("comment text NOT NULL,");
createGlobalFilesTable.append("CONSTRAINT global_files_multi_unique UNIQUE(global_reference_set_id, value)"); createGlobalFilesTable.append("CONSTRAINT global_files_multi_unique UNIQUE(global_reference_set_id, value) ON CONFLICT IGNORE,");
createGlobalFilesTable.append("foreign key (global_reference_set_id) references global_reference_sets(id) on update set null on delete set null"); createGlobalFilesTable.append("foreign key (global_reference_set_id) references global_reference_sets(id) ON UPDATE SET NULL ON DELETE SET NULL");
createGlobalFilesTable.append(")"); createGlobalFilesTable.append(")");
String globalFilesIdx1 = "CREATE INDEX IF NOT EXISTS global_files_value ON global_files (value)"; String globalFilesIdx1 = "CREATE INDEX IF NOT EXISTS global_files_value ON global_files (value)";
@ -321,9 +321,9 @@ public final class SqliteEamDbSettings {
createArtifactInstancesTableTemplate.append("file_path text NOT NULL,"); createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
createArtifactInstancesTableTemplate.append("known_status text NOT NULL,"); createArtifactInstancesTableTemplate.append("known_status text NOT NULL,");
createArtifactInstancesTableTemplate.append("comment text NOT NULL,"); createArtifactInstancesTableTemplate.append("comment text NOT NULL,");
createArtifactInstancesTableTemplate.append("CONSTRAINT %s_instances_multi_unique UNIQUE(case_id, data_source_id, value, file_path),"); createArtifactInstancesTableTemplate.append("CONSTRAINT %s_instances_multi_unique UNIQUE(case_id, data_source_id, value, file_path) ON CONFLICT IGNORE,");
createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) on update set null on delete set null,"); createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) on update set null on delete set null"); createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
createArtifactInstancesTableTemplate.append(")"); createArtifactInstancesTableTemplate.append(")");
// TODO: do we need any more indices? // TODO: do we need any more indices?

View File

@ -48,8 +48,8 @@ import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskDataException;
/** /**
* Listen for case events and update entries in the Central Repository * Listen for case events and update entries in the Central Repository database
* database accordingly * accordingly
*/ */
@Messages({"caseeventlistener.evidencetag=Evidence"}) @Messages({"caseeventlistener.evidencetag=Evidence"})
public class CaseEventListener implements PropertyChangeListener { public class CaseEventListener implements PropertyChangeListener {
@ -75,7 +75,8 @@ public class CaseEventListener implements PropertyChangeListener {
|| (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) || (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)
|| (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)
|| (af.getKnown() == TskData.FileKnown.KNOWN) || (af.getKnown() == TskData.FileKnown.KNOWN)
|| (af.isDir() == true)) { || (af.isDir() == true)
|| (!af.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC))) {
break; break;
} }
@ -108,7 +109,7 @@ public class CaseEventListener implements PropertyChangeListener {
new EamDataSource(deviceId, dsName), new EamDataSource(deviceId, dsName),
af.getParentPath() + af.getName(), af.getParentPath() + af.getName(),
tagAdded.getComment(), tagAdded.getComment(),
EamArtifactInstance.KnownStatus.BAD, TskData.FileKnown.BAD,
EamArtifactInstance.GlobalStatus.LOCAL EamArtifactInstance.GlobalStatus.LOCAL
); );
eamArtifact.addInstance(cei); eamArtifact.addInstance(cei);

View File

@ -49,8 +49,8 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskDataException;
/** /**
* Ingest module for inserting entries into the Central Repository * Ingest module for inserting entries into the Central Repository database on
* database on ingest of a data source * ingest of a data source
*/ */
@Messages({"IngestModule.prevcases.text=Previous Cases"}) @Messages({"IngestModule.prevcases.text=Previous Cases"})
class IngestModule implements FileIngestModule { class IngestModule implements FileIngestModule {
@ -83,7 +83,8 @@ class IngestModule implements FileIngestModule {
|| (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) || (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)
|| (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)
|| (af.getKnown() == TskData.FileKnown.KNOWN) || (af.getKnown() == TskData.FileKnown.KNOWN)
|| (af.isDir() == true)) { || (af.isDir() == true)
|| (!af.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC))) {
return ProcessResult.OK; return ProcessResult.OK;
} }
@ -134,7 +135,7 @@ class IngestModule implements FileIngestModule {
eamDataSource, eamDataSource,
af.getParentPath() + af.getName(), af.getParentPath() + af.getName(),
"", "",
EamArtifactInstance.KnownStatus.UNKNOWN, TskData.FileKnown.UNKNOWN,
EamArtifactInstance.GlobalStatus.LOCAL EamArtifactInstance.GlobalStatus.LOCAL
); );
eamArtifact.addInstance(cefi); eamArtifact.addInstance(cefi);

View File

@ -49,7 +49,7 @@ AddNewOrganizationDialog.bnOK.text=OK
AddNewOrganizationDialog.tfName.tooltip=POC Name AddNewOrganizationDialog.tfName.tooltip=POC Name
ManageTagsDialog.okButton.text=OK ManageTagsDialog.okButton.text=OK
ManageTagsDialog.cancelButton.text=Cancel ManageTagsDialog.cancelButton.text=Cancel
ManageArtifactTypesDialog.taInstructionsMsg.text=Enable one or more correlation properties to use for correlation during Ingest. 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.pnDatabaseConnectionSettings.border.title=Database Settings

View File

@ -60,6 +60,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.datamodel.TskData;
/** /**
* Instances of this class allow a user to select an existing hash database and * Instances of this class allow a user to select an existing hash database and
@ -515,11 +516,11 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
} }
// insert hashes // insert hashes
EamArtifactInstance.KnownStatus knownStatus = EamArtifactInstance.KnownStatus.UNKNOWN; TskData.FileKnown knownStatus = TskData.FileKnown.UNKNOWN;
if (knownRadioButton.isSelected()) { if (knownRadioButton.isSelected()) {
knownStatus = EamArtifactInstance.KnownStatus.KNOWN; knownStatus = TskData.FileKnown.KNOWN;
} else if (knownBadRadioButton.isSelected()) { } else if (knownBadRadioButton.isSelected()) {
knownStatus = EamArtifactInstance.KnownStatus.BAD; knownStatus = TskData.FileKnown.BAD;
} }
String errorMessage = Bundle.ImportHashDatabaseDialog_errorMessage_failedToOpenHashDbMsg(selectedFilePath); String errorMessage = Bundle.ImportHashDatabaseDialog_errorMessage_failedToOpenHashDbMsg(selectedFilePath);
@ -529,7 +530,7 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
// 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();
} catch (EamDbException ex) { } catch (EamDbException | UnknownHostException ex) {
Logger.getLogger(ImportHashDatabaseDialog.class.getName()).log(Level.SEVERE, errorMessage, ex); Logger.getLogger(ImportHashDatabaseDialog.class.getName()).log(Level.SEVERE, errorMessage, ex);
lbWarningMsg.setText(ex.getMessage()); lbWarningMsg.setText(ex.getMessage());
} }
@ -564,12 +565,12 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog {
private class ImportHashDatabaseWorker extends SwingWorker<Void, Void> { private class ImportHashDatabaseWorker extends SwingWorker<Void, Void> {
private final File file; private final File file;
private final EamArtifactInstance.KnownStatus knownStatus; private final TskData.FileKnown knownStatus;
private final int globalSetID; private final int globalSetID;
private final ProgressHandle progress; private final ProgressHandle progress;
private final EamArtifact.Type contentType; private final EamArtifact.Type contentType;
public ImportHashDatabaseWorker(String filename, EamArtifactInstance.KnownStatus knownStatus, int globalSetID, EamArtifact.Type contentType) throws EamDbException { public ImportHashDatabaseWorker(String filename, TskData.FileKnown knownStatus, int globalSetID, EamArtifact.Type contentType) throws EamDbException, UnknownHostException {
this.file = new File(filename); this.file = new File(filename);
this.knownStatus = knownStatus; this.knownStatus = knownStatus;
this.globalSetID = globalSetID; this.globalSetID = globalSetID;

View File

@ -32,8 +32,14 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import javax.swing.event.TableColumnModelListener;
import javax.swing.text.JTextComponent;
import javax.swing.text.View;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.util.Lookup; import org.openide.util.Lookup;
@ -52,8 +58,8 @@ import org.netbeans.swing.etable.ETable;
/** /**
* Instances of this class display the BlackboardArtifacts associated with the * Instances of this class display the BlackboardArtifacts associated with the
* Content represented by a Node. Each BlackboardArtifact is rendered displayed in a JTable * Content represented by a Node. Each BlackboardArtifact is rendered displayed
* representation of its BlackboardAttributes. * in a JTable representation of its BlackboardAttributes.
*/ */
@ServiceProvider(service = DataContentViewer.class, position = 3) @ServiceProvider(service = DataContentViewer.class, position = 3)
public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer { public class DataContentViewerArtifact extends javax.swing.JPanel implements DataContentViewer {
@ -78,6 +84,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
Bundle.DataContentViewerArtifact_attrsTableHeader_value(), Bundle.DataContentViewerArtifact_attrsTableHeader_value(),
Bundle.DataContentViewerArtifact_attrsTableHeader_sources()}; Bundle.DataContentViewerArtifact_attrsTableHeader_sources()};
private static final int[] COLUMN_WIDTHS = {100, 800, 100}; private static final int[] COLUMN_WIDTHS = {100, 800, 100};
private static final int CELL_BOTTOM_MARGIN = 5;
public DataContentViewerArtifact() { public DataContentViewerArtifact() {
initResultsTable(); initResultsTable();
@ -85,6 +92,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
resultsTableScrollPane.setViewportView(resultsTable); resultsTableScrollPane.setViewportView(resultsTable);
customizeComponents(); customizeComponents();
resetComponents(); resetComponents();
resultsTable.setDefaultRenderer(Object.class, new MultiLineTableCellRenderer());
} }
private void initResultsTable() { private void initResultsTable() {
@ -100,11 +108,71 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
resultsTable.getTableHeader().setReorderingAllowed(false); resultsTable.getTableHeader().setReorderingAllowed(false);
resultsTable.setColumnHidingAllowed(false); resultsTable.setColumnHidingAllowed(false);
resultsTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION); resultsTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
updateColumnSizes(); resultsTable.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
@Override
public void columnAdded(TableColumnModelEvent e) {
} }
private void updateColumnSizes() { @Override
public void columnRemoved(TableColumnModelEvent e) {
}
@Override
public void columnMoved(TableColumnModelEvent e) {
}
@Override
public void columnMarginChanged(ChangeEvent e) {
updateRowHeights(); //When the user changes column width we may need to resize row height
}
@Override
public void columnSelectionChanged(ListSelectionEvent e) {
}
});
resultsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN); resultsTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN);
}
/**
* Sets the row heights to the heights of the content in their Value column.
*/
private void updateRowHeights() {
int valueColIndex = -1;
for (int col = 0; col < resultsTable.getColumnCount(); col++) {
if (resultsTable.getColumnName(col).equals(COLUMN_HEADERS[1])) {
valueColIndex = col;
}
}
if (valueColIndex != -1) {
for (int row = 0; row < resultsTable.getRowCount(); row++) {
Component comp = resultsTable.prepareRenderer(
resultsTable.getCellRenderer(row, valueColIndex), row, valueColIndex);
final int rowHeight;
if (comp instanceof JTextComponent) {
final JTextComponent tc = (JTextComponent) comp;
final View rootView = tc.getUI().getRootView(tc);
java.awt.Insets i = tc.getInsets(null);
rootView.setSize(resultsTable.getColumnModel().getColumn(valueColIndex)
.getPreferredWidth() - i.left - i.right,
Integer.MAX_VALUE);
rowHeight = (int) rootView.getPreferredSpan(View.Y_AXIS);
} else {
rowHeight = comp.getPreferredSize().height;
}
if (rowHeight > 0) {
resultsTable.setRowHeight(row, rowHeight + CELL_BOTTOM_MARGIN);
}
}
}
}
/**
* Update the column widths so that the Value column has most of the space.
*/
private void updateColumnSizes() {
Enumeration<TableColumn> columns = resultsTable.getColumnModel().getColumns(); Enumeration<TableColumn> columns = resultsTable.getColumnModel().getColumns();
while (columns.hasMoreElements()) { while (columns.hasMoreElements()) {
TableColumn col = columns.nextElement(); TableColumn col = columns.nextElement();
@ -551,6 +619,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel());
tModel.setDataVector(viewUpdate.tableContents.getRows(), COLUMN_HEADERS); tModel.setDataVector(viewUpdate.tableContents.getRows(), COLUMN_HEADERS);
updateColumnSizes(); updateColumnSizes();
updateRowHeights();
resultsTable.clearSelection(); resultsTable.clearSelection();
this.setCursor(null); this.setCursor(null);
@ -568,6 +637,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel()); DefaultTableModel tModel = ((DefaultTableModel) resultsTable.getModel());
tModel.setDataVector(waitRow, COLUMN_HEADERS); tModel.setDataVector(waitRow, COLUMN_HEADERS);
updateColumnSizes(); updateColumnSizes();
updateRowHeights();
resultsTable.clearSelection(); resultsTable.clearSelection();
// The output of the previous task is no longer relevant. // The output of the previous task is no longer relevant.
if (currentTask != null) { if (currentTask != null) {
@ -758,4 +828,27 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
} }
} }
} }
/**
* TableCellRenderer for displaying multiline text.
*/
private class MultiLineTableCellRenderer implements javax.swing.table.TableCellRenderer {
@Override
public Component getTableCellRendererComponent(javax.swing.JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
javax.swing.JTextArea jtex = new javax.swing.JTextArea();
if (value instanceof String) {
jtex.setText((String) value);
jtex.setLineWrap(true);
jtex.setWrapStyleWord(true);
}
//cell backgroud color when selected
if (isSelected) {
jtex.setBackground(javax.swing.UIManager.getColor("Table.selectionBackground"));
} else {
jtex.setBackground(javax.swing.UIManager.getColor("Table.background"));
}
return jtex;
}
}
} }

View File

@ -51,7 +51,9 @@ import org.sleuthkit.datamodel.TskData;
/** /**
* Filters database results by file extension. * Filters database results by file extension.
*/ */
public final class FileTypesByExtension implements AutopsyVisitableItem { public final class FileTypesByExtension implements AutopsyVisitableItem {
private static final Logger LOGGER = Logger.getLogger(FileTypesByExtension.class.getName());
private final SleuthkitCase skCase; private final SleuthkitCase skCase;
@ -72,33 +74,25 @@ import org.sleuthkit.datamodel.TskData;
* Listens for case and ingest invest. Updates observers when events are * Listens for case and ingest invest. Updates observers when events are
* fired. FileType and FileTypes nodes are all listening to this. * fired. FileType and FileTypes nodes are all listening to this.
*/ */
private static class FileTypesByExtObservable extends Observable { static private class FileTypesByExtObservable extends Observable {
private FileTypesByExtObservable() { private boolean showCounts = true;
private final PropertyChangeListener pcl;
private FileTypesByExtObservable(SleuthkitCase skCase) {
super(); super();
IngestManager.getInstance().addIngestJobEventListener(pcl); this.pcl = (PropertyChangeEvent evt) -> {
IngestManager.getInstance().addIngestModuleEventListener(pcl);
Case.addPropertyChangeListener(pcl);
}
private void removeListeners() {
deleteObservers();
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removePropertyChangeListener(pcl);
}
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
String eventType = evt.getPropertyName(); String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString()) || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString()) || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString()) || 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 * Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked out. * different way of handling the closing of cases is worked
* Currently, remote events may be received for a case that is * out. Currently, remote events may be received for a case
* already closed. * that is already closed.
*/ */
try { try {
Case.getCurrentCase(); Case.getCurrentCase();
shouldShowCounts(skCase);
update(); update();
} catch (IllegalStateException notUsed) { } catch (IllegalStateException notUsed) {
/** /**
@ -113,6 +107,39 @@ import org.sleuthkit.datamodel.TskData;
} }
}; };
IngestManager.getInstance().addIngestJobEventListener(pcl);
IngestManager.getInstance().addIngestModuleEventListener(pcl);
Case.addPropertyChangeListener(pcl);
}
/**
* Should the nodes show counts?
*
*
* @return True, unless the DB has more than 200k rows.
*/
private boolean shouldShowCounts(SleuthkitCase skCase) {
if (showCounts) {
try {
if (skCase.countFilesWhere("1=1") > 200000) {
showCounts = false;
}
} catch (TskCoreException tskCoreException) {
showCounts = false;
LOGGER.log(Level.SEVERE, "Error counting files.", tskCoreException);
}
}
return showCounts;
}
private void removeListeners() {
deleteObservers();
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removePropertyChangeListener(pcl);
}
private void update() { private void update() {
setChanged(); setChanged();
notifyObservers(); notifyObservers();
@ -146,7 +173,7 @@ import org.sleuthkit.datamodel.TskData;
* @param o Observable that was created by a higher-level node that * @param o Observable that was created by a higher-level node that
* provides updates on events * provides updates on events
*/ */
private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, Observable o) { private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) {
super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName()));
this.filter = filter; this.filter = filter;
init(); init();
@ -206,7 +233,7 @@ import org.sleuthkit.datamodel.TskData;
private final SleuthkitCase skCase; private final SleuthkitCase skCase;
private final FileTypesByExtension.RootFilter filter; private final FileTypesByExtension.RootFilter filter;
private final Observable notifier; private final FileTypesByExtObservable notifier;
/** /**
* *
@ -215,12 +242,12 @@ import org.sleuthkit.datamodel.TskData;
* @param o Observable that provides updates based on events * @param o Observable that provides updates based on events
* being fired (or null if one needs to be created) * being fired (or null if one needs to be created)
*/ */
private FileTypesByExtNodeChildren(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, Observable o) { private FileTypesByExtNodeChildren(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) {
super(); super();
this.skCase = skCase; this.skCase = skCase;
this.filter = filter; this.filter = filter;
if (o == null) { if (o == null) {
this.notifier = new FileTypesByExtObservable(); this.notifier = new FileTypesByExtObservable(skCase);
} else { } else {
this.notifier = o; this.notifier = o;
} }
@ -263,6 +290,7 @@ import org.sleuthkit.datamodel.TskData;
FileTypesByExtension.SearchFilterInterface filter; FileTypesByExtension.SearchFilterInterface filter;
SleuthkitCase skCase; SleuthkitCase skCase;
private final FileTypesByExtObservable notifier;
/** /**
* *
@ -271,10 +299,11 @@ import org.sleuthkit.datamodel.TskData;
* @param o Observable that sends updates when the child factories * @param o Observable that sends updates when the child factories
* should refresh * should refresh
*/ */
FileExtensionNode(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) { FileExtensionNode(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, FileTypesByExtObservable o) {
super(Children.create(new FileExtensionNodeChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); super(Children.create(new FileExtensionNodeChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName()));
this.filter = filter; this.filter = filter;
this.skCase = skCase; this.skCase = skCase;
this.notifier = o;
init(); init();
o.addObserver(new ByExtNodeObserver()); o.addObserver(new ByExtNodeObserver());
} }
@ -295,8 +324,10 @@ import org.sleuthkit.datamodel.TskData;
} }
private void updateDisplayName() { private void updateDisplayName() {
final long count = FileExtensionNodeChildren.calculateItems(skCase, filter); final String count = notifier.shouldShowCounts(skCase)
super.setDisplayName(filter.getDisplayName() + " (" + count + ")"); ? " (" + Long.toString(FileExtensionNodeChildren.calculateItems(skCase, filter)) + ")"
: "";
super.setDisplayName(filter.getDisplayName() + count);
} }
@Override @Override

View File

@ -71,41 +71,18 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
private final HashMap<String, List<String>> existingMimeTypes = new HashMap<>(); private final HashMap<String, List<String>> existingMimeTypes = new HashMap<>();
private static final Logger LOGGER = Logger.getLogger(FileTypesByMimeType.class.getName()); private static final Logger LOGGER = Logger.getLogger(FileTypesByMimeType.class.getName());
private boolean showCounts = true;
private void removeListeners() { private void removeListeners() {
deleteObservers(); deleteObservers();
IngestManager.getInstance().removeIngestJobEventListener(pcl); IngestManager.getInstance().removeIngestJobEventListener(pcl);
Case.removePropertyChangeListener(pcl); Case.removePropertyChangeListener(pcl);
} }
/* /*
* The pcl is in the class because it has the easiest mechanisms to add and * The pcl is in the class because it has the easiest mechanisms to add and
* remove itself during its life cycles. * remove itself during its life cycles.
*/ */
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { private final PropertyChangeListener pcl;
String eventType = evt.getPropertyName();
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();
populateHashMap();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
if (evt.getNewValue() == null) {
removeListeners();
}
}
};
/** /**
* Retrieve the media types by retrieving the keyset from the hashmap. * Retrieve the media types by retrieving the keyset from the hashmap.
@ -140,7 +117,6 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
existingMimeTypes.clear(); existingMimeTypes.clear();
if (skCase == null) { if (skCase == null) {
return; return;
} }
try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(allDistinctMimeTypesQuery.toString())) { try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(allDistinctMimeTypesQuery.toString())) {
@ -170,12 +146,59 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
} }
FileTypesByMimeType(SleuthkitCase skCase) { FileTypesByMimeType(SleuthkitCase skCase) {
this.pcl = (PropertyChangeEvent evt) -> {
String eventType = evt.getPropertyName();
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();
shouldShowCounts(skCase);
populateHashMap();
} catch (IllegalStateException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
if (evt.getNewValue() == null) {
removeListeners();
}
}
};
IngestManager.getInstance().addIngestJobEventListener(pcl); IngestManager.getInstance().addIngestJobEventListener(pcl);
Case.addPropertyChangeListener(pcl); Case.addPropertyChangeListener(pcl);
this.skCase = skCase; this.skCase = skCase;
populateHashMap(); populateHashMap();
} }
/**
* Should the nodes show counts?
*
*
* @return True, unless the DB has more than 200k rows.
*/
private boolean shouldShowCounts(final SleuthkitCase skCase) {
if (showCounts) {
try {
if (skCase.countFilesWhere("1=1") > 200000) {
showCounts = false;
}
} catch (TskCoreException tskCoreException) {
showCounts = false;
LOGGER.log(Level.SEVERE, "Error counting files.", tskCoreException);
}
}
return showCounts;
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> v) { public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -358,10 +381,12 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
* results * results
*/ */
private void updateDisplayName(String mimeType) { private void updateDisplayName(String mimeType) {
final long count = new MediaSubTypeNodeChildren(mimeType).calculateItems(skCase, mimeType); final String count = shouldShowCounts(skCase)
? " (" + Long.toString(new MediaSubTypeNodeChildren(mimeType).calculateItems(skCase, mimeType)) + ")"
: "";
String[] mimeTypeParts = mimeType.split("/"); String[] mimeTypeParts = mimeType.split("/");
//joins up all remaining parts of the mimeType into one sub-type string //joins up all remaining parts of the mimeType into one sub-type string
super.setDisplayName(StringUtils.join(ArrayUtils.subarray(mimeTypeParts, 1, mimeTypeParts.length), "/") + " (" + count + ")"); super.setDisplayName(StringUtils.join(ArrayUtils.subarray(mimeTypeParts, 1, mimeTypeParts.length), "/") + count);
} }
/** /**

View File

@ -236,10 +236,10 @@ KeywordSearchGlobalLanguageSettingsPanel.ingestSettingsLabel.text=Ingest setting
KeywordSearchGlobalLanguageSettingsPanel.enableUTF16Checkbox.text=Enable UTF16LE and UTF16BE string extraction KeywordSearchGlobalLanguageSettingsPanel.enableUTF16Checkbox.text=Enable UTF16LE and UTF16BE string extraction
KeywordSearchGlobalLanguageSettingsPanel.languagesLabel.text=Enabled scripts (languages): KeywordSearchGlobalLanguageSettingsPanel.languagesLabel.text=Enabled scripts (languages):
KeywordSearchGlobalSearchSettingsPanel.timeRadioButton1.toolTipText=20 mins. (fastest ingest time) KeywordSearchGlobalSearchSettingsPanel.timeRadioButton1.toolTipText=20 mins. (fastest ingest time)
KeywordSearchGlobalSearchSettingsPanel.timeRadioButton1.text=20 minutes KeywordSearchGlobalSearchSettingsPanel.timeRadioButton1.text=20 minutes (slowest feedback, fastest ingest)
KeywordSearchGlobalSearchSettingsPanel.timeRadioButton2.toolTipText=10 minutes (faster overall ingest time than default) KeywordSearchGlobalSearchSettingsPanel.timeRadioButton2.toolTipText=10 minutes (faster overall ingest time than default)
KeywordSearchGlobalSearchSettingsPanel.timeRadioButton2.text=10 minutes KeywordSearchGlobalSearchSettingsPanel.timeRadioButton2.text=10 minutes (slower feedback, faster ingest)
KeywordSearchGlobalSearchSettingsPanel.frequencyLabel.text=Results update frequency during ingest (we have not seen significant performance differences between 5, 10, or 20 minute intervals): KeywordSearchGlobalSearchSettingsPanel.frequencyLabel.text=Results update frequency during ingest:
KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.toolTipText=Requires Hash DB service to had run previously, or be selected for next ingest. KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.toolTipText=Requires Hash DB service to had run previously, or be selected for next ingest.
KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.text=Do not add files in NSRL (known files) to keyword index during ingest KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.text=Do not add files in NSRL (known files) to keyword index during ingest
KeywordSearchGlobalSearchSettingsPanel.informationLabel.text=Information KeywordSearchGlobalSearchSettingsPanel.informationLabel.text=Information
@ -249,7 +249,7 @@ KeywordSearchGlobalSearchSettingsPanel.filesIndexedLabel.text=Files in keyword i
KeywordSearchGlobalSearchSettingsPanel.showSnippetsCB.text=Show Keyword Preview in Keyword Search Results (will result in longer search times) KeywordSearchGlobalSearchSettingsPanel.showSnippetsCB.text=Show Keyword Preview in Keyword Search Results (will result in longer search times)
KeywordSearchGlobalSearchSettingsPanel.chunksValLabel.text=0 KeywordSearchGlobalSearchSettingsPanel.chunksValLabel.text=0
KeywordSearchGlobalSearchSettingsPanel.timeRadioButton4.toolTipText=1 minute (overall ingest time will be longest) KeywordSearchGlobalSearchSettingsPanel.timeRadioButton4.toolTipText=1 minute (overall ingest time will be longest)
KeywordSearchGlobalSearchSettingsPanel.timeRadioButton4.text_1=1 minute KeywordSearchGlobalSearchSettingsPanel.timeRadioButton4.text_1=1 minute (faster feedback, longest ingest)
KeywordSearchGlobalSearchSettingsPanel.chunksLabel.text=Chunks in keyword index: KeywordSearchGlobalSearchSettingsPanel.chunksLabel.text=Chunks in keyword index:
KeywordSearchGlobalSearchSettingsPanel.timeRadioButton3.toolTipText=5 minutes (overall ingest time will be longer) KeywordSearchGlobalSearchSettingsPanel.timeRadioButton3.toolTipText=5 minutes (overall ingest time will be longer)
KeywordSearchGlobalSearchSettingsPanel.timeRadioButton3.text=5 minutes (default) KeywordSearchGlobalSearchSettingsPanel.timeRadioButton3.text=5 minutes (default)