mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 10:17:41 +00:00
3080 Moved all actions as a result of CaseEventLister to background thread pool
This commit is contained in:
parent
32af6d3b49
commit
2fb71f2ff0
@ -85,6 +85,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.core.UserPreferencesException;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.CoreComponentControl;
|
||||
import org.sleuthkit.autopsy.coreutils.DriveUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.ExecUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
@ -1645,7 +1646,7 @@ public class Case {
|
||||
} else {
|
||||
future.cancel(true);
|
||||
}
|
||||
Case.shutDownTaskExecutor(caseLockingExecutor);
|
||||
ExecUtil.shutDownTaskExecutor(caseLockingExecutor);
|
||||
} catch (CancellationException discarded) {
|
||||
/*
|
||||
* The create/open task has been cancelled. Wait for it to finish,
|
||||
@ -1654,7 +1655,7 @@ public class Case {
|
||||
* will have been closed and the case directory lock released will
|
||||
* have been released.
|
||||
*/
|
||||
Case.shutDownTaskExecutor(caseLockingExecutor);
|
||||
ExecUtil.shutDownTaskExecutor(caseLockingExecutor);
|
||||
throw new CaseActionCancelledException(Bundle.Case_exceptionMessage_cancelledByUser());
|
||||
} catch (ExecutionException ex) {
|
||||
/*
|
||||
@ -1664,7 +1665,7 @@ public class Case {
|
||||
* case will have been closed and the case directory lock released
|
||||
* will have been released.
|
||||
*/
|
||||
Case.shutDownTaskExecutor(caseLockingExecutor);
|
||||
ExecUtil.shutDownTaskExecutor(caseLockingExecutor);
|
||||
throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex);
|
||||
} finally {
|
||||
progressIndicator.finish();
|
||||
@ -1992,7 +1993,7 @@ public class Case {
|
||||
* would be possible to start the next task before the current
|
||||
* task responded to a cancellation request.
|
||||
*/
|
||||
shutDownTaskExecutor(executor);
|
||||
ExecUtil.shutDownTaskExecutor(executor);
|
||||
progressIndicator.finish();
|
||||
}
|
||||
|
||||
@ -2063,7 +2064,7 @@ public class Case {
|
||||
} catch (ExecutionException ex) {
|
||||
throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex);
|
||||
} finally {
|
||||
shutDownTaskExecutor(caseLockingExecutor);
|
||||
ExecUtil.shutDownTaskExecutor(caseLockingExecutor);
|
||||
progressIndicator.finish();
|
||||
}
|
||||
}
|
||||
@ -2174,7 +2175,7 @@ public class Case {
|
||||
Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
|
||||
}
|
||||
} finally {
|
||||
shutDownTaskExecutor(executor);
|
||||
ExecUtil.shutDownTaskExecutor(executor);
|
||||
progressIndicator.finish();
|
||||
}
|
||||
}
|
||||
@ -2231,41 +2232,6 @@ public class Case {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down a task executor service, waiting until all tasks are
|
||||
* terminated. The current policy is to wait for the tasks to finish so that
|
||||
* the case for which the executor is running can be left in a consistent
|
||||
* state.
|
||||
*
|
||||
* @param executor The executor.
|
||||
*/
|
||||
private static void shutDownTaskExecutor(ExecutorService executor) {
|
||||
executor.shutdown();
|
||||
boolean taskCompleted = false;
|
||||
while (!taskCompleted) {
|
||||
try {
|
||||
taskCompleted = executor.awaitTermination(EXECUTOR_AWAIT_TIMEOUT_SECS, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ignored) {
|
||||
/*
|
||||
* The current policy is to wait for the task to finish so that
|
||||
* the case can be left in a consistent state.
|
||||
*
|
||||
* For a specific example of the motivation for this policy,
|
||||
* note that a application service (Solr search service)
|
||||
* experienced an error condition when opening case resources
|
||||
* that left the service blocked uninterruptibly on a socket
|
||||
* read. This eventually led to a mysterious "freeze" as the
|
||||
* user-cancelled service task continued to run holdiong a lock
|
||||
* that a UI thread soon tried to acquire. Thus it has been
|
||||
* deemed better to make the "freeze" happen in a more
|
||||
* informative way, i.e., with the progress indicator for the
|
||||
* unfinished task on the screen, if a similar error condition
|
||||
* arises again.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A case operation Cancel button listener for use with a
|
||||
* ModalDialogProgressIndicator when running with a GUI.
|
||||
|
@ -18,9 +18,12 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.centralrepository.eventlisteners;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
@ -39,6 +42,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
|
||||
import org.sleuthkit.autopsy.coreutils.ExecUtil;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
@ -53,9 +57,19 @@ import org.sleuthkit.datamodel.TskDataException;
|
||||
* accordingly
|
||||
*/
|
||||
@Messages({"caseeventlistener.evidencetag=Evidence"})
|
||||
public class CaseEventListener implements PropertyChangeListener {
|
||||
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";
|
||||
|
||||
CaseEventListener() {
|
||||
jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(CASE_EVENT_THREAD_NAME).build());
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
ExecUtil.shutDownTaskExecutor(jobProcessingExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
@ -69,250 +83,24 @@ public class CaseEventListener implements PropertyChangeListener {
|
||||
switch (Case.Events.valueOf(evt.getPropertyName())) {
|
||||
case CONTENT_TAG_ADDED:
|
||||
case CONTENT_TAG_DELETED: {
|
||||
if (!EamDb.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractFile af;
|
||||
TskData.FileKnown knownStatus;
|
||||
String comment;
|
||||
if (Case.Events.valueOf(evt.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) evt;
|
||||
final ContentTag tagAdded = tagAddedEvent.getAddedTag();
|
||||
|
||||
if (dbManager.getBadTags().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) evt;
|
||||
long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
|
||||
|
||||
String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
|
||||
if (!dbManager.getBadTags().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.getCurrentCase().getSleuthkitCase().getContentById(contentID);
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
|
||||
|
||||
if (tags.stream()
|
||||
.map(tag -> tag.getName().getDisplayName())
|
||||
.filter(dbManager.getBadTags()::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 ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to find content", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(af,
|
||||
knownStatus, comment);
|
||||
|
||||
if (eamArtifact != null) {
|
||||
// send update to Central Repository db
|
||||
Runnable r = new KnownStatusChangeRunner(eamArtifact, knownStatus);
|
||||
// TODO: send r into a thread pool instead
|
||||
Thread t = new Thread(r);
|
||||
t.start();
|
||||
}
|
||||
} // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED
|
||||
jobProcessingExecutor.submit(new ContentTagTask(dbManager, evt));
|
||||
}
|
||||
break;
|
||||
|
||||
case BLACKBOARD_ARTIFACT_TAG_DELETED:
|
||||
case BLACKBOARD_ARTIFACT_TAG_ADDED: {
|
||||
if (!EamDb.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Content content;
|
||||
BlackboardArtifact bbArtifact;
|
||||
TskData.FileKnown knownStatus;
|
||||
String comment;
|
||||
if (Case.Events.valueOf(evt.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) evt;
|
||||
final BlackboardArtifactTag tagAdded = tagAddedEvent.getAddedTag();
|
||||
|
||||
if (dbManager.getBadTags().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
|
||||
// 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) evt;
|
||||
long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
|
||||
long artifactID = tagDeletedEvent.getDeletedTagInfo().getArtifactID();
|
||||
|
||||
String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
|
||||
if (!dbManager.getBadTags().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 = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID);
|
||||
bbArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactID);
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
|
||||
|
||||
if (tags.stream()
|
||||
.map(tag -> tag.getName().getDisplayName())
|
||||
.filter(dbManager.getBadTags()::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;
|
||||
}
|
||||
}
|
||||
|
||||
if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<CorrelationAttribute> convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbArtifact, true, true);
|
||||
for (CorrelationAttribute eamArtifact : convertedArtifacts) {
|
||||
eamArtifact.getInstances().get(0).setComment(comment);
|
||||
Runnable r = new KnownStatusChangeRunner(eamArtifact, knownStatus);
|
||||
// TODO: send r into a thread pool instead
|
||||
Thread t = new Thread(r);
|
||||
t.start();
|
||||
}
|
||||
|
||||
} // BLACKBOARD_ARTIFACT_TAG_ADDED, BLACKBOARD_ARTIFACT_TAG_DELETED
|
||||
jobProcessingExecutor.submit(new BlackboardTagTask(dbManager, evt));
|
||||
}
|
||||
break;
|
||||
|
||||
case DATA_SOURCE_ADDED: {
|
||||
if (!EamDb.isEnabled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) evt;
|
||||
Content newDataSource = dataSourceAddedEvent.getDataSource();
|
||||
|
||||
try {
|
||||
String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
|
||||
CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
|
||||
if (null == correlationCase) {
|
||||
dbManager.newCase(Case.getCurrentCase());
|
||||
correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
|
||||
}
|
||||
if (null == dbManager.getDataSourceDetails(correlationCase, deviceId)) {
|
||||
dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource));
|
||||
}
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
|
||||
} catch (TskCoreException | TskDataException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS
|
||||
}
|
||||
} // DATA_SOURCE_ADDED
|
||||
jobProcessingExecutor.submit(new DataSourceAddedTask(dbManager, evt));
|
||||
}
|
||||
break;
|
||||
|
||||
case CURRENT_CASE: {
|
||||
/*
|
||||
* A case has been opened if evt.getOldValue() is null and
|
||||
* evt.getNewValue() is a valid Case.
|
||||
*/
|
||||
if ((null == evt.getOldValue()) && (evt.getNewValue() instanceof Case)) {
|
||||
Case curCase = (Case) evt.getNewValue();
|
||||
IngestEventsListener.resetCeModuleInstanceCount();
|
||||
try {
|
||||
// only add default evidence tag if case is open and it doesn't already exist in the tags list.
|
||||
if (Case.isCaseOpen()
|
||||
&& Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream()
|
||||
.map(tag -> tag.getDisplayName())
|
||||
.filter(tagName -> Bundle.caseeventlistener_evidencetag().equals(tagName))
|
||||
.collect(Collectors.toList())
|
||||
.isEmpty()) {
|
||||
curCase.getServices().getTagsManager().addTagName(Bundle.caseeventlistener_evidencetag());
|
||||
}
|
||||
} catch (TagsManager.TagNameAlreadyExistsException ex) {
|
||||
LOGGER.info("Evidence tag already exists"); // NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error adding tag.", ex); // NON-NLS
|
||||
}
|
||||
|
||||
CorrelationCase curCeCase = new CorrelationCase(
|
||||
-1,
|
||||
curCase.getName(), // unique case ID
|
||||
EamOrganization.getDefault(),
|
||||
curCase.getDisplayName(),
|
||||
curCase.getCreatedDate(),
|
||||
curCase.getNumber(),
|
||||
curCase.getExaminer(),
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
if (!EamDb.isEnabled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
// NOTE: Cannot determine if the opened case is a new case or a reopened case,
|
||||
// so check for existing name in DB and insert if missing.
|
||||
CorrelationCase existingCase = dbManager.getCaseByUUID(curCeCase.getCaseUUID());
|
||||
|
||||
if (null == existingCase) {
|
||||
dbManager.newCase(curCeCase);
|
||||
}
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
} // CURRENT_CASE
|
||||
jobProcessingExecutor.submit(new CurrentCaseTask(dbManager, evt));
|
||||
}
|
||||
break;
|
||||
|
||||
case NAME: {
|
||||
@ -340,4 +128,296 @@ public class CaseEventListener implements PropertyChangeListener {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private final class ContentTagTask implements Runnable {
|
||||
|
||||
private final EamDb dbManager;
|
||||
private final PropertyChangeEvent event;
|
||||
|
||||
private ContentTagTask(EamDb db, PropertyChangeEvent evt) {
|
||||
dbManager = db;
|
||||
event = evt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!EamDb.isEnabled()) {
|
||||
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();
|
||||
|
||||
if (dbManager.getBadTags().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 (!dbManager.getBadTags().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.getCurrentCase().getSleuthkitCase().getContentById(contentID);
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
|
||||
|
||||
if (tags.stream()
|
||||
.map(tag -> tag.getName().getDisplayName())
|
||||
.filter(dbManager.getBadTags()::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 ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to find content", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(af,
|
||||
knownStatus, comment);
|
||||
|
||||
if (eamArtifact != null) {
|
||||
// send update to Central Repository db
|
||||
try {
|
||||
dbManager.setArtifactInstanceKnownStatus(eamArtifact, knownStatus);
|
||||
} catch (EamDbException ex) {
|
||||
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 {
|
||||
|
||||
private final EamDb dbManager;
|
||||
private final PropertyChangeEvent event;
|
||||
|
||||
private BlackboardTagTask(EamDb db, PropertyChangeEvent evt) {
|
||||
dbManager = db;
|
||||
event = evt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!EamDb.isEnabled()) {
|
||||
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 (dbManager.getBadTags().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
|
||||
// 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 (!dbManager.getBadTags().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 = Case.getCurrentCase().getSleuthkitCase().getContentById(contentID);
|
||||
bbArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(artifactID);
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
|
||||
|
||||
if (tags.stream()
|
||||
.map(tag -> tag.getName().getDisplayName())
|
||||
.filter(dbManager.getBadTags()::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;
|
||||
}
|
||||
}
|
||||
|
||||
if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<CorrelationAttribute> convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbArtifact, true, true);
|
||||
for (CorrelationAttribute eamArtifact : convertedArtifacts) {
|
||||
eamArtifact.getInstances().get(0).setComment(comment);
|
||||
try {
|
||||
dbManager.setArtifactInstanceKnownStatus(eamArtifact, knownStatus);
|
||||
} catch (EamDbException 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
|
||||
|
||||
}
|
||||
|
||||
private final class DataSourceAddedTask implements Runnable {
|
||||
|
||||
private final EamDb dbManager;
|
||||
private final PropertyChangeEvent event;
|
||||
|
||||
private DataSourceAddedTask(EamDb db, PropertyChangeEvent evt) {
|
||||
dbManager = db;
|
||||
event = evt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!EamDb.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) event;
|
||||
Content newDataSource = dataSourceAddedEvent.getDataSource();
|
||||
|
||||
try {
|
||||
String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
|
||||
CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
|
||||
if (null == correlationCase) {
|
||||
dbManager.newCase(Case.getCurrentCase());
|
||||
correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
|
||||
}
|
||||
if (null == dbManager.getDataSourceDetails(correlationCase, deviceId)) {
|
||||
dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource));
|
||||
}
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
|
||||
} catch (TskCoreException | TskDataException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS
|
||||
}
|
||||
} // DATA_SOURCE_ADDED
|
||||
}
|
||||
|
||||
private final class CurrentCaseTask implements Runnable {
|
||||
|
||||
private final EamDb dbManager;
|
||||
private final PropertyChangeEvent event;
|
||||
|
||||
private CurrentCaseTask(EamDb db, PropertyChangeEvent evt) {
|
||||
dbManager = db;
|
||||
event = evt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
/*
|
||||
* A case has been opened if evt.getOldValue() is null and
|
||||
* evt.getNewValue() is a valid Case.
|
||||
*/
|
||||
if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) {
|
||||
Case curCase = (Case) event.getNewValue();
|
||||
IngestEventsListener.resetCeModuleInstanceCount();
|
||||
try {
|
||||
// only add default evidence tag if case is open and it doesn't already exist in the tags list.
|
||||
if (Case.isCaseOpen()
|
||||
&& Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream()
|
||||
.map(tag -> tag.getDisplayName())
|
||||
.filter(tagName -> Bundle.caseeventlistener_evidencetag().equals(tagName))
|
||||
.collect(Collectors.toList())
|
||||
.isEmpty()) {
|
||||
curCase.getServices().getTagsManager().addTagName(Bundle.caseeventlistener_evidencetag());
|
||||
}
|
||||
} catch (TagsManager.TagNameAlreadyExistsException ex) {
|
||||
LOGGER.info("Evidence tag already exists"); // NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error adding tag.", ex); // NON-NLS
|
||||
}
|
||||
|
||||
CorrelationCase curCeCase = new CorrelationCase(
|
||||
-1,
|
||||
curCase.getName(), // unique case ID
|
||||
EamOrganization.getDefault(),
|
||||
curCase.getDisplayName(),
|
||||
curCase.getCreatedDate(),
|
||||
curCase.getNumber(),
|
||||
curCase.getExaminer(),
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
if (!EamDb.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// NOTE: Cannot determine if the opened case is a new case or a reopened case,
|
||||
// so check for existing name in DB and insert if missing.
|
||||
CorrelationCase existingCase = dbManager.getCaseByUUID(curCeCase.getCaseUUID());
|
||||
|
||||
if (null == existingCase) {
|
||||
dbManager.newCase(curCeCase);
|
||||
}
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
} // CURRENT_CASE
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.centralrepository.eventlisteners;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import org.openide.modules.ModuleInstall;
|
||||
import org.openide.util.actions.CallableSystemAction;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
@ -32,7 +31,7 @@ public class Installer extends ModuleInstall {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(Installer.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final PropertyChangeListener pcl = new CaseEventListener();
|
||||
private final CaseEventListener pcl = new CaseEventListener();
|
||||
private final IngestEventsListener ieListener = new IngestEventsListener();
|
||||
|
||||
private static Installer instance;
|
||||
@ -71,6 +70,7 @@ public class Installer extends ModuleInstall {
|
||||
//module is being unloaded
|
||||
|
||||
Case.removePropertyChangeListener(pcl);
|
||||
pcl.shutdown();
|
||||
ieListener.uninstallListeners();
|
||||
|
||||
// TODO: remove thread pool
|
||||
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.centralrepository.eventlisteners;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||
import org.sleuthkit.datamodel.TskData.FileKnown;
|
||||
|
||||
/**
|
||||
* Thread to send info to remote DB that tags a file as known, unknown, or notable.
|
||||
*/
|
||||
public class KnownStatusChangeRunner implements Runnable {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(KnownStatusChangeRunner.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final CorrelationAttribute artifact;
|
||||
private final FileKnown knownStatus;
|
||||
|
||||
public KnownStatusChangeRunner(CorrelationAttribute artifact, FileKnown knownStatus) {
|
||||
this.artifact = artifact;
|
||||
this.knownStatus = knownStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!EamDb.isEnabled()) {
|
||||
LOGGER.log(Level.WARNING, "Central Repository database not configured"); // NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
EamDb dbManager = EamDb.getInstance();
|
||||
dbManager.setArtifactInstanceKnownStatus(this.artifact, this.knownStatus);
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ import java.io.InputStreamReader;
|
||||
import java.io.Writer;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
@ -212,6 +213,40 @@ public final class ExecUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down a task executor service, waiting until all tasks are
|
||||
* terminated. The current policy is to wait for the tasks to finish so that
|
||||
* the case for which the executor is running can be left in a consistent
|
||||
* state.
|
||||
*
|
||||
* @param executor The executor.
|
||||
*/
|
||||
public static void shutDownTaskExecutor(ExecutorService executor) {
|
||||
executor.shutdown();
|
||||
boolean taskCompleted = false;
|
||||
while (!taskCompleted) {
|
||||
try {
|
||||
taskCompleted = executor.awaitTermination(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNITS);
|
||||
} catch (InterruptedException ignored) {
|
||||
/*
|
||||
* The current policy is to wait for the task to finish so that
|
||||
* the case can be left in a consistent state.
|
||||
*
|
||||
* For a specific example of the motivation for this policy,
|
||||
* note that a application service (Solr search service)
|
||||
* experienced an error condition when opening case resources
|
||||
* that left the service blocked uninterruptibly on a socket
|
||||
* read. This eventually led to a mysterious "freeze" as the
|
||||
* user-cancelled service task continued to run holdiong a lock
|
||||
* that a UI thread soon tried to acquire. Thus it has been
|
||||
* deemed better to make the "freeze" happen in a more
|
||||
* informative way, i.e., with the progress indicator for the
|
||||
* unfinished task on the screen, if a similar error condition
|
||||
* arises again.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* EVERYTHING FOLLOWING THIS LINE IS DEPRECATED AND SLATED FOR REMOVAL
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user