Merge pull request #5896 from gdicristofaro/6359-removeCommenting

6359 remove commenting
This commit is contained in:
Richard Cordovano 2020-05-18 09:30:28 -04:00 committed by GitHub
commit 137c3ff74d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 356 additions and 265 deletions

View File

@ -41,6 +41,7 @@ import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
@ -81,7 +82,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
private static final Cache<Pair<CentralRepoAccountType, String>, CentralRepoAccount> accountsCache = CacheBuilder.newBuilder()
.expireAfterWrite(ACCOUNTS_CACHE_TIMEOUT, TimeUnit.MINUTES).
build();
private boolean isCRTypeCacheInitialized;
private static final Cache<Integer, CorrelationAttributeInstance.Type> typeCache = CacheBuilder.newBuilder().build();
private static final Cache<String, CorrelationCase> caseCacheByUUID = CacheBuilder.newBuilder()
@ -104,8 +105,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
static final int DEFAULT_BULK_THRESHHOLD = 1000;
private static final int QUERY_STR_MAX_LEN = 1000;
/**
* Connect to the DB and initialize it.
*
@ -136,6 +136,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
* Get an ephemeral connection.
*/
protected abstract Connection getEphemeralConnection();
/**
* Add a new name/value pair in the db_info table.
*
@ -222,7 +223,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
* Reset the contents of the caches associated with EamDb results.
*/
public final void clearCaches() {
synchronized(typeCache) {
synchronized (typeCache) {
typeCache.invalidateAll();
isCRTypeCacheInitialized = false;
}
@ -1016,27 +1017,26 @@ abstract class RdbmsCentralRepo implements CentralRepository {
// @@@ We should cache the case and data source IDs in memory
String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
boolean artifactHasAnAccount = CentralRepoDbUtil.correlationAttribHasAnAccount(eamArtifact.getCorrelationType());
String sql;
// _instance table for accounts have an additional account_id column
if (artifactHasAnAccount) {
sql = "INSERT INTO "
+ tableName
+ "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id, account_id) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?) "
+ getConflictClause();
}
else {
sql = "INSERT INTO "
+ tableName
+ "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?) "
+ getConflictClause();
sql = "INSERT INTO "
+ tableName
+ "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id, account_id) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?) "
+ getConflictClause();
} else {
sql = "INSERT INTO "
+ tableName
+ "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?) "
+ getConflictClause();
}
try (Connection conn = connect();
PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
if (!eamArtifact.getCorrelationValue().isEmpty()) {
preparedStatement.setInt(1, eamArtifact.getCorrelationCase().getID());
preparedStatement.setInt(2, eamArtifact.getCorrelationDataSource().getID());
@ -1050,7 +1050,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
preparedStatement.setString(6, eamArtifact.getComment());
}
preparedStatement.setLong(7, eamArtifact.getFileObjectId());
// set in the accountId only for artifacts that represent accounts
if (artifactHasAnAccount) {
if (eamArtifact.getAccountId() >= 0) {
@ -1065,21 +1065,21 @@ abstract class RdbmsCentralRepo implements CentralRepository {
} catch (SQLException ex) {
throw new CentralRepoException("Error inserting new artifact into artifacts table.", ex); // NON-NLS
}
}
}
/**
* Gets the Central Repo account for the given account type and account ID.
* Create a new account first, if one doesn't exist
*
* @param accountType account type
* @param accountUniqueID unique account identifier
*
* @return A matching account, either existing or newly created.
*
* @throws TskCoreException exception thrown if a critical error occurs
* within TSK core
*/
/**
* Gets the Central Repo account for the given account type and account ID.
* Create a new account first, if one doesn't exist
*
* @param accountType account type
* @param accountUniqueID unique account identifier
*
* @return A matching account, either existing or newly created.
*
* @throws TskCoreException exception thrown if a critical error occurs
* within TSK core
*/
@Override
public CentralRepoAccount getOrCreateAccount(CentralRepoAccountType crAccountType, String accountUniqueID) throws CentralRepoException {
// Get the account fom the accounts table
@ -1105,56 +1105,53 @@ abstract class RdbmsCentralRepo implements CentralRepository {
return account;
}
@Override
public CentralRepoAccountType getAccountTypeByName(String accountTypeName) throws CentralRepoException {
try {
return accountTypesCache.get(accountTypeName, () -> getCRAccountTypeFromDb(accountTypeName));
} catch (CacheLoader.InvalidCacheLoadException | ExecutionException ex) {
throw new CentralRepoException("Error looking up CR account type in cache.", ex);
}
throw new CentralRepoException("Error looking up CR account type in cache.", ex);
}
}
@Override
public Collection<CentralRepoAccountType> getAllAccountTypes() throws CentralRepoException {
Collection<CentralRepoAccountType> accountTypes = new ArrayList<>();
String sql = "SELECT * FROM account_types";
try ( Connection conn = connect();
PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
Collection<CentralRepoAccountType> accountTypes = new ArrayList<>();
String sql = "SELECT * FROM account_types";
try (Connection conn = connect();
PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
try (ResultSet resultSet = preparedStatement.executeQuery();) {
while (resultSet.next()) {
Account.Type acctType = new Account.Type(resultSet.getString("type_name"), resultSet.getString("display_name"));
CentralRepoAccountType crAccountType = new CentralRepoAccountType(resultSet.getInt("id"), acctType, resultSet.getInt("correlation_type_id"));
accountTypes.add(crAccountType);
}
}
}
} catch (SQLException ex) {
throw new CentralRepoException("Error getting account types from central repository.", ex); // NON-NLS
}
}
return accountTypes;
}
/**
* Gets the CR account type for the specified type name.
*
*
* @param accountTypeName account type name to look for
*
* @return CR account type
*
* @throws CentralRepoException
*
* @throws CentralRepoException
*/
private CentralRepoAccountType getCRAccountTypeFromDb(String accountTypeName) throws CentralRepoException {
String sql = "SELECT * FROM account_types WHERE type_name = ?";
try ( Connection conn = connect();
PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
try (Connection conn = connect();
PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
preparedStatement.setString(1, accountTypeName);
try (ResultSet resultSet = preparedStatement.executeQuery();) {
@ -1169,24 +1166,27 @@ abstract class RdbmsCentralRepo implements CentralRepository {
}
} catch (SQLException ex) {
throw new CentralRepoException("Error getting correlation type by id.", ex); // NON-NLS
}
}
}
/**
* Get the CR account with the given account type and the unique account identifier.
* Looks in the cache first.
* If not found in cache, reads from the database and saves in cache.
*
* Returns null if the account is not found in the cache and not in the database.
*
* @param crAccountType account type to look for
* Get the CR account with the given account type and the unique account
* identifier. Looks in the cache first. If not found in cache, reads from
* the database and saves in cache.
*
* Returns null if the account is not found in the cache and not in the
* database.
*
* @param crAccountType account type to look for
* @param accountUniqueID unique account id
* @return CentralRepoAccount for the give type/id. May return null if not found.
*
* @throws CentralRepoException
*
* @return CentralRepoAccount for the give type/id. May return null if not
* found.
*
* @throws CentralRepoException
*/
private CentralRepoAccount getAccount(CentralRepoAccountType crAccountType, String accountUniqueID) throws CentralRepoException {
CentralRepoAccount crAccount = accountsCache.getIfPresent(Pair.of(crAccountType, accountUniqueID));
if (crAccount == null) {
crAccount = getCRAccountFromDb(crAccountType, accountUniqueID);
@ -1194,30 +1194,29 @@ abstract class RdbmsCentralRepo implements CentralRepository {
accountsCache.put(Pair.of(crAccountType, accountUniqueID), crAccount);
}
}
return crAccount;
}
/**
* Get the Account with the given account type and account identifier,
* from the database.
* Get the Account with the given account type and account identifier, from
* the database.
*
* @param accountType account type
* @param accountType account type
* @param accountUniqueID unique account identifier
*
* @return Account, returns NULL is no matching account found
*
* @throws TskCoreException exception thrown if a critical error occurs
* within TSK core
* within TSK core
*/
private CentralRepoAccount getCRAccountFromDb(CentralRepoAccountType crAccountType, String accountUniqueID) throws CentralRepoException {
CentralRepoAccount account = null;
String sql = "SELECT * FROM accounts WHERE account_type_id = ? AND account_unique_identifier = ?";
try ( Connection connection = connect();
PreparedStatement preparedStatement = connection.prepareStatement(sql);) {
try (Connection connection = connect();
PreparedStatement preparedStatement = connection.prepareStatement(sql);) {
preparedStatement.setInt(1, crAccountType.getAccountTypeId());
preparedStatement.setString(2, accountUniqueID);
@ -1233,8 +1232,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
return account;
}
private void checkAddArtifactInstanceNulls(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
if (eamArtifact == null) {
throw new CentralRepoException("CorrelationAttribute is null");
@ -1575,7 +1573,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
synchronized (bulkArtifacts) {
if (bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())) == null) {
bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()), new ArrayList<>());
bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()), new ArrayList<>());
}
bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact);
bulkArtifactsCount++;
@ -2002,8 +2000,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
String sqlUpdate
= "UPDATE "
+ tableName
+ " SET known_status=?, comment=? "
+ "WHERE id=?";
+ " SET known_status=? WHERE id=?";
try {
preparedQuery = conn.prepareStatement(sqlQuery);
@ -2017,15 +2014,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
preparedUpdate = conn.prepareStatement(sqlUpdate);
preparedUpdate.setByte(1, knownStatus.getFileKnownValue());
// NOTE: if the user tags the same instance as BAD multiple times,
// the comment from the most recent tagging is the one that will
// prevail in the DB.
if ("".equals(eamArtifact.getComment())) {
preparedUpdate.setNull(2, Types.INTEGER);
} else {
preparedUpdate.setString(2, eamArtifact.getComment());
}
preparedUpdate.setInt(3, instance_id);
preparedUpdate.setInt(2, instance_id);
preparedUpdate.executeUpdate();
} else {
@ -2332,8 +2321,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
HashHitInfo found = new HashHitInfo(hashFound, "", "");
found.addComment(comment);
return found;
}
else {
} else {
return null;
}
} catch (SQLException ex) {
@ -2344,8 +2332,6 @@ abstract class RdbmsCentralRepo implements CentralRepository {
CentralRepoDbUtil.closeConnection(conn);
}
}
/**
* Check if the given value is in a specific reference set
@ -2516,7 +2502,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
CentralRepoDbUtil.closeConnection(conn);
}
}
/**
* Process a SELECT query
*
@ -2554,7 +2540,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
CentralRepoDbUtil.closeResultSet(resultSet);
CentralRepoDbUtil.closeConnection(conn);
}
}
}
@Override
public void executeInsertSQL(String insertClause) throws CentralRepoException {
@ -2597,7 +2583,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
throw new CentralRepoException(String.format("Error running SQL %s, exception = %s", selectSQL, ex.getMessage()), ex);
}
}
@Override
public CentralRepoOrganization newOrganization(CentralRepoOrganization eamOrg) throws CentralRepoException {
if (eamOrg == null) {
@ -2737,15 +2723,16 @@ abstract class RdbmsCentralRepo implements CentralRepository {
}
/**
* Queries the examiner table for the given user name.
* Adds a row if the user is not found in the examiner table.
* Queries the examiner table for the given user name. Adds a row if the
* user is not found in the examiner table.
*
* @param examinerLoginName user name to look for.
*
* @return CentralRepoExaminer for the given user name.
*
* @throws CentralRepoException If there is an error in looking up or
* inserting the user in the examiners table.
* inserting the user in the examiners table.
*/
@Override
public CentralRepoExaminer getOrInsertExaminer(String examinerLoginName) throws CentralRepoException {
@ -2770,7 +2757,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
default:
throw new CentralRepoException(String.format("Cannot add examiner to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); //NON-NLS
}
statement.execute(insertSQL);
statement.execute(insertSQL);
// Query the table again to get the row for the user
try (ResultSet resultSet2 = statement.executeQuery(querySQL)) {
@ -2790,7 +2777,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName, ex);
}
}
/**
* Update an existing organization.
*
@ -3185,7 +3172,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
typeId = newCorrelationTypeKnownId(newType);
}
synchronized(typeCache) {
synchronized (typeCache) {
typeCache.put(newType.getId(), newType);
}
return typeId;
@ -3402,7 +3389,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
preparedStatement.setInt(5, aType.getId());
preparedStatement.executeUpdate();
synchronized(typeCache) {
synchronized (typeCache) {
typeCache.put(aType.getId(), aType);
}
} catch (SQLException ex) {
@ -3426,7 +3413,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
@Override
public CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId) throws CentralRepoException {
try {
synchronized(typeCache) {
synchronized (typeCache) {
return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
}
} catch (CacheLoader.InvalidCacheLoadException ignored) {
@ -3437,7 +3424,6 @@ abstract class RdbmsCentralRepo implements CentralRepository {
}
}
/**
* Get the EamArtifact.Type that has the given Type.Id from the central repo
*
@ -3476,24 +3462,25 @@ abstract class RdbmsCentralRepo implements CentralRepository {
}
/**
* Reads the correlation types from the database and loads them up in the cache.
*
* Reads the correlation types from the database and loads them up in the
* cache.
*
* @throws CentralRepoException If there is an error.
*/
private void getCorrelationTypesFromCr() throws CentralRepoException {
// clear out the cache
synchronized(typeCache) {
synchronized (typeCache) {
typeCache.invalidateAll();
isCRTypeCacheInitialized = false;
}
String sql = "SELECT * FROM correlation_types";
try ( Connection conn = connect();
PreparedStatement preparedStatement = conn.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();) {
synchronized(typeCache) {
String sql = "SELECT * FROM correlation_types";
try (Connection conn = connect();
PreparedStatement preparedStatement = conn.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();) {
synchronized (typeCache) {
while (resultSet.next()) {
CorrelationAttributeInstance.Type aType = getCorrelationTypeFromResultSet(resultSet);
typeCache.put(aType.getId(), aType);
@ -3502,9 +3489,9 @@ abstract class RdbmsCentralRepo implements CentralRepository {
}
} catch (SQLException ex) {
throw new CentralRepoException("Error getting correlation types.", ex); // NON-NLS
}
}
}
/**
* Convert a ResultSet to a EamCase object
*
@ -3662,13 +3649,13 @@ abstract class RdbmsCentralRepo implements CentralRepository {
case POSTGRESQL:
return "INSERT " + sql + " ON CONFLICT DO NOTHING"; //NON-NLS
case SQLITE:
return "INSERT OR IGNORE " + sql;
return "INSERT OR IGNORE " + sql;
default:
throw new CentralRepoException("Unknown Central Repo DB platform" + CentralRepoDbManager.getSavedDbChoice().getDbPlatform());
}
}
/**
* Determine if a specific column already exists in a specific table
*
@ -3781,7 +3768,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
*/
if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS
final String addSsidTableTemplate = RdbmsCentralRepoFactory.getCreateArtifactInstancesTableTemplate(selectedPlatform);
final String addCaseIdIndexTemplate = RdbmsCentralRepoFactory.getAddCaseIdIndexTemplate();
final String addDataSourceIdIndexTemplate = RdbmsCentralRepoFactory.getAddDataSourceIdIndexTemplate();
@ -3801,7 +3788,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
default:
throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
}
final String dataSourcesTableName = "data_sources";
final String dataSourceObjectIdColumnName = "datasource_obj_id";
if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
@ -3966,7 +3953,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
// Upgrade to 1.4
(new CentralRepoDbUpgrader13To14()).upgradeSchema(dbSchemaVersion, conn);
// Upgrade to 1.5
(new CentralRepoDbUpgrader14To15()).upgradeSchema(dbSchemaVersion, conn);

View File

@ -27,7 +27,6 @@ import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
@ -55,6 +54,7 @@ import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.datamodel.Tag;
import org.sleuthkit.autopsy.events.AutopsyEvent;
/**
@ -67,12 +67,12 @@ final class CaseEventListener implements PropertyChangeListener {
private static final Logger LOGGER = Logger.getLogger(CaseEventListener.class.getName());
private final ExecutorService jobProcessingExecutor;
private static final String CASE_EVENT_THREAD_NAME = "Case-Event-Listener-%d";
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(
Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED,
Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED, Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED,
Case.Events.CONTENT_TAG_ADDED, Case.Events.CONTENT_TAG_DELETED,
Case.Events.DATA_SOURCE_ADDED,
Case.Events.DATA_SOURCE_ADDED,
Case.Events.TAG_DEFINITION_CHANGED,
Case.Events.CURRENT_CASE,
Case.Events.DATA_SOURCE_NAME_CHANGED);
@ -90,7 +90,7 @@ final class CaseEventListener implements PropertyChangeListener {
if (!(evt instanceof AutopsyEvent) || (((AutopsyEvent) evt).getSourceType() != AutopsyEvent.SourceType.LOCAL)) {
return;
}
CentralRepository dbManager;
try {
dbManager = CentralRepository.getInstance();
@ -98,7 +98,7 @@ final class CaseEventListener implements PropertyChangeListener {
LOGGER.log(Level.SEVERE, "Failed to get instance of db manager.", ex);
return;
}
// If any changes are made to which event types are handled the change
// must also be made to CASE_EVENTS_OF_INTEREST.
switch (Case.Events.valueOf(evt.getPropertyName())) {
@ -132,7 +132,7 @@ final class CaseEventListener implements PropertyChangeListener {
break;
}
}
/*
* Add all of our Case Event Listeners to the case.
*/
@ -147,6 +147,46 @@ final class CaseEventListener implements PropertyChangeListener {
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, this);
}
/**
* Returns true if the tag has a notable status.
*
* @param t The tag to use in determination.
*
* @return Whether or not it is a notable tag.
*/
private static boolean isNotableTag(Tag t) {
return (t != null && isNotableTagName(t.getName()));
}
/**
* Returns true if the tag name has a notable status.
*
* @param t The tag name to use in determination.
*
* @return Whether or not it is a notable tag name.
*/
private static boolean isNotableTagName(TagName t) {
return (t != null && TagsManager.getNotableTagDisplayNames().contains(t.getDisplayName()));
}
/**
* Searches a list of tags for a tag with a notable status.
*
* @param tags The tags to search.
*
* @return Whether or not the list contains a notable tag.
*/
private static boolean hasNotableTag(List<? extends Tag> tags) {
if (tags == null) {
return false;
}
return tags.stream()
.filter(CaseEventListener::isNotableTag)
.findFirst()
.isPresent();
}
private final class ContentTagTask implements Runnable {
private final CentralRepository dbManager;
@ -163,72 +203,98 @@ final class CaseEventListener implements PropertyChangeListener {
return;
}
AbstractFile af;
TskData.FileKnown knownStatus;
String comment;
if (Case.Events.valueOf(event.getPropertyName()) == Case.Events.CONTENT_TAG_ADDED) {
// For added tags, we want to change the known status to BAD if the
// tag that was just added is in the list of central repo tags.
final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) event;
final ContentTag tagAdded = tagAddedEvent.getAddedTag();
Case.Events curEventType = Case.Events.valueOf(event.getPropertyName());
if (curEventType == Case.Events.CONTENT_TAG_ADDED && event instanceof ContentTagAddedEvent) {
handleTagAdded((ContentTagAddedEvent) event);
} else if (curEventType == Case.Events.CONTENT_TAG_DELETED && event instanceof ContentTagDeletedEvent) {
handleTagDeleted((ContentTagDeletedEvent) event);
} else {
LOGGER.log(Level.SEVERE,
String.format("Received an event %s of type %s and was expecting either CONTENT_TAG_ADDED or CONTENT_TAG_DELETED.",
event, curEventType));
}
}
if (TagsManager.getNotableTagDisplayNames().contains(tagAdded.getName().getDisplayName())) {
if (tagAdded.getContent() instanceof AbstractFile) {
af = (AbstractFile) tagAdded.getContent();
knownStatus = TskData.FileKnown.BAD;
comment = tagAdded.getComment();
} else {
LOGGER.log(Level.WARNING, "Error updating non-file object");
return;
}
} else {
// The added tag isn't flagged as bad in central repo, so do nothing
return;
}
} else { // CONTENT_TAG_DELETED
// For deleted tags, we want to set the file status to UNKNOWN if:
// - The tag that was just removed is notable in central repo
// - There are no remaining tags that are notable
final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) event;
long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
if (!TagsManager.getNotableTagDisplayNames().contains(tagName)) {
// If the tag that got removed isn't on the list of central repo tags, do nothing
return;
}
try {
// Get the remaining tags on the content object
Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(contentID);
TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
if (tags.stream()
.map(tag -> tag.getName().getDisplayName())
.filter(TagsManager.getNotableTagDisplayNames()::contains)
.collect(Collectors.toList())
.isEmpty()) {
// There are no more bad tags on the object
if (content instanceof AbstractFile) {
af = (AbstractFile) content;
knownStatus = TskData.FileKnown.UNKNOWN;
comment = "";
} else {
LOGGER.log(Level.WARNING, "Error updating non-file object");
return;
}
} else {
// There's still at least one bad tag, so leave the known status as is
return;
}
} catch (TskCoreException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Failed to find content", ex);
return;
}
private void handleTagDeleted(ContentTagDeletedEvent evt) {
// ensure tag deleted event has a valid content id
if (evt.getDeletedTagInfo() == null) {
LOGGER.log(Level.SEVERE, "ContentTagDeletedEvent did not have valid content to provide a content id.");
return;
}
try {
// obtain content
Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(evt.getDeletedTagInfo().getContentID());
if (content == null) {
LOGGER.log(Level.WARNING,
String.format("Unable to get content for item with content id: %d.", evt.getDeletedTagInfo().getContentID()));
return;
}
// then handle the event
handleTagChange(content);
} catch (NoCurrentCaseException | TskCoreException ex) {
LOGGER.log(Level.WARNING, "Error updating non-file object: " + evt.getDeletedTagInfo().getContentID(), ex);
}
}
private void handleTagAdded(ContentTagAddedEvent evt) {
// ensure tag added event has a valid content id
if (evt.getAddedTag() == null || evt.getAddedTag().getContent() == null) {
LOGGER.log(Level.SEVERE, "ContentTagAddedEvent did not have valid content to provide a content id.");
return;
}
// then handle the event
handleTagChange(evt.getAddedTag().getContent());
}
/**
* When a tag is added or deleted, check if there are other notable tags
* for the item. If there are, set known status as notable. If not set
* status as unknown.
*
* @param content The content for the tag that was added or deleted.
*/
private void handleTagChange(Content content) {
AbstractFile af = null;
try {
af = Case.getCurrentCaseThrows().getSleuthkitCase().getAbstractFileById(content.getId());
} catch (NoCurrentCaseException | TskCoreException ex) {
Long contentID = (content != null) ? content.getId() : null;
LOGGER.log(Level.WARNING, "Error updating non-file object: " + contentID, ex);
}
if (af == null) {
return;
}
try {
// Get the tags on the content object
TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager();
if (hasNotableTag(tagsManager.getContentTagsByContent(content))) {
// if there is a notable tag on the object, set content known status to bad
setContentKnownStatus(af, TskData.FileKnown.BAD);
} else {
// otherwise, set to unknown
setContentKnownStatus(af, TskData.FileKnown.UNKNOWN);
}
} catch (TskCoreException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Failed to obtain tags manager for case.", ex);
}
}
/**
* Sets the known status for the correlation attribute instance for the
* given abstract file.
*
* @param af The abstract file for which to set the correlation
* attribute instance.
* @param knownStatus The new known status for the correlation attribute
* instance.
*/
private void setContentKnownStatus(AbstractFile af, TskData.FileKnown knownStatus) {
final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile(af);
if (eamArtifact != null) {
@ -239,7 +305,7 @@ final class CaseEventListener implements PropertyChangeListener {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
}
}
} // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED
}
}
private final class BlackboardTagTask implements Runnable {
@ -258,87 +324,125 @@ final class CaseEventListener implements PropertyChangeListener {
return;
}
Content content;
BlackboardArtifact bbArtifact;
TskData.FileKnown knownStatus;
String comment;
if (Case.Events.valueOf(event.getPropertyName()) == Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED) {
// For added tags, we want to change the known status to BAD if the
// tag that was just added is in the list of central repo tags.
final BlackBoardArtifactTagAddedEvent tagAddedEvent = (BlackBoardArtifactTagAddedEvent) event;
final BlackboardArtifactTag tagAdded = tagAddedEvent.getAddedTag();
if (TagsManager.getNotableTagDisplayNames().contains(tagAdded.getName().getDisplayName())) {
content = tagAdded.getContent();
bbArtifact = tagAdded.getArtifact();
knownStatus = TskData.FileKnown.BAD;
comment = tagAdded.getComment();
} else {
// The added tag isn't flagged as bad in central repo, so do nothing
return;
}
} else { //BLACKBOARD_ARTIFACT_TAG_DELETED
Case openCase;
try {
openCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
return;
}
// For deleted tags, we want to set the file status to UNKNOWN if:
// - The tag that was just removed is notable in central repo
// - There are no remaining tags that are notable
final BlackBoardArtifactTagDeletedEvent tagDeletedEvent = (BlackBoardArtifactTagDeletedEvent) event;
long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
long artifactID = tagDeletedEvent.getDeletedTagInfo().getArtifactID();
String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
if (!TagsManager.getNotableTagDisplayNames().contains(tagName)) {
// If the tag that got removed isn't on the list of central repo tags, do nothing
return;
}
try {
// Get the remaining tags on the artifact
content = openCase.getSleuthkitCase().getContentById(contentID);
bbArtifact = openCase.getSleuthkitCase().getBlackboardArtifact(artifactID);
TagsManager tagsManager = openCase.getServices().getTagsManager();
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
if (tags.stream()
.map(tag -> tag.getName().getDisplayName())
.filter(TagsManager.getNotableTagDisplayNames()::contains)
.collect(Collectors.toList())
.isEmpty()) {
// There are no more bad tags on the object
knownStatus = TskData.FileKnown.UNKNOWN;
comment = "";
} else {
// There's still at least one bad tag, so leave the known status as is
return;
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to find content", ex);
return;
}
Case.Events curEventType = Case.Events.valueOf(event.getPropertyName());
if (curEventType == Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED && event instanceof BlackBoardArtifactTagAddedEvent) {
handleTagAdded((BlackBoardArtifactTagAddedEvent) event);
} else if (curEventType == Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED && event instanceof BlackBoardArtifactTagDeletedEvent) {
handleTagDeleted((BlackBoardArtifactTagDeletedEvent) event);
} else {
LOGGER.log(Level.WARNING,
String.format("Received an event %s of type %s and was expecting either CONTENT_TAG_ADDED or CONTENT_TAG_DELETED.",
event, curEventType));
}
}
if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
private void handleTagDeleted(BlackBoardArtifactTagDeletedEvent evt) {
// ensure tag deleted event has a valid content id
if (evt.getDeletedTagInfo() == null) {
LOGGER.log(Level.SEVERE, "BlackBoardArtifactTagDeletedEvent did not have valid content to provide a content id.");
return;
}
try {
Case openCase = Case.getCurrentCaseThrows();
// obtain content
Content content = openCase.getSleuthkitCase().getContentById(evt.getDeletedTagInfo().getContentID());
if (content == null) {
LOGGER.log(Level.WARNING,
String.format("Unable to get content for item with content id: %d.", evt.getDeletedTagInfo().getContentID()));
return;
}
// obtain blackboard artifact
BlackboardArtifact bbArtifact = openCase.getSleuthkitCase().getBlackboardArtifact(evt.getDeletedTagInfo().getArtifactID());
if (bbArtifact == null) {
LOGGER.log(Level.WARNING,
String.format("Unable to get blackboard artifact for item with artifact id: %d.", evt.getDeletedTagInfo().getArtifactID()));
return;
}
// then handle the event
handleTagChange(content, bbArtifact);
} catch (NoCurrentCaseException | TskCoreException ex) {
LOGGER.log(Level.WARNING, "Error updating non-file object.", ex);
}
}
private void handleTagAdded(BlackBoardArtifactTagAddedEvent evt) {
// ensure tag added event has a valid content id
if (evt.getAddedTag() == null || evt.getAddedTag().getContent() == null || evt.getAddedTag().getArtifact() == null) {
LOGGER.log(Level.SEVERE, "BlackBoardArtifactTagAddedEvent did not have valid content to provide a content id.");
return;
}
// then handle the event
handleTagChange(evt.getAddedTag().getContent(), evt.getAddedTag().getArtifact());
}
/**
* When a tag is added or deleted, check if there are other notable tags
* for the item. If there are, set known status as notable. If not set
* status as unknown.
*
* @param content The content for the tag that was added or deleted.
* @param bbArtifact The artifact for the tag that was added or deleted.
*/
private void handleTagChange(Content content, BlackboardArtifact bbArtifact) {
Case openCase;
try {
openCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
return;
}
try {
if (isKnownFile(content)) {
return;
}
TagsManager tagsManager = openCase.getServices().getTagsManager();
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
if (hasNotableTag(tags)) {
setArtifactKnownStatus(bbArtifact, TskData.FileKnown.BAD);
} else {
setArtifactKnownStatus(bbArtifact, TskData.FileKnown.UNKNOWN);
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to obtain tags manager for case.", ex);
return;
}
}
/**
* Determines if the content is an abstract file and is a known file.
*
* @param content The content to assess.
*
* @return True if an abstract file and a known file.
*/
private boolean isKnownFile(Content content) {
return ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN));
}
/**
* Sets the known status of a blackboard artifact in the central
* repository.
*
* @param bbArtifact The blackboard artifact to set known status.
* @param knownStatus The new known status.
*/
private void setArtifactKnownStatus(BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) {
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact);
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
eamArtifact.setComment(comment);
try {
dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
} catch (CentralRepoException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
}
}
} // BLACKBOARD_ARTIFACT_TAG_ADDED, BLACKBOARD_ARTIFACT_TAG_DELETED
}
}
@ -439,8 +543,8 @@ final class CaseEventListener implements PropertyChangeListener {
//if the file will have no tags with a status which would prevent the current status from being changed
if (!hasTagWithConflictingKnownStatus) {
Content taggedContent = contentTag.getContent();
if (taggedContent instanceof AbstractFile) {
final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile((AbstractFile)taggedContent);
if (taggedContent instanceof AbstractFile) {
final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile((AbstractFile) taggedContent);
if (eamArtifact != null) {
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
}