diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java index 92c23d77c8..9bbccb3317 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationDataSource.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2019 Basis Technology Corp. + * Copyright 2015-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -98,32 +98,33 @@ public class CorrelationDataSource implements Serializable { } /** - * Create a CorrelationDataSource object from a TSK Content object. This - * will add it to the central repository. + * Creates a central repository data source object from a case database data + * source. If the data source is not already present in the central + * repository, it is added. * - * @param correlationCase the current CorrelationCase used for ensuring - * uniqueness of DataSource - * @param dataSource the sleuthkit datasource that is being added to - * the central repository + * @param correlationCase The central repository case associated with the + * data aosurce. + * @param dataSource The case database data source. * - * @return + * @return The cnetral repository data source. * - * @throws CentralRepoException + * @throws CentralRepoException This exception is thrown if there is an + * error creating the central repository data + * source. */ public static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource) throws CentralRepoException { + if (!CentralRepository.isEnabled()) { + throw new CentralRepoException("Central repository is not enabled, cannot create central repository data source, "); + } + Case curCase; try { curCase = Case.getCurrentCaseThrows(); } catch (NoCurrentCaseException ex) { - throw new CentralRepoException("Autopsy case is closed"); - } - - CorrelationDataSource correlationDataSource = null; - boolean useCR = CentralRepository.isEnabled(); - if (useCR) { - correlationDataSource = CentralRepository.getInstance().getDataSource(correlationCase, dataSource.getId()); + throw new CentralRepoException("Error getting current case", ex); } + CorrelationDataSource correlationDataSource = CentralRepository.getInstance().getDataSource(correlationCase, dataSource.getId()); if (correlationDataSource == null) { String deviceId; String md5 = null; @@ -131,7 +132,7 @@ public class CorrelationDataSource implements Serializable { String sha256 = null; try { deviceId = curCase.getSleuthkitCase().getDataSource(dataSource.getId()).getDeviceId(); - + if (dataSource instanceof Image) { Image image = (Image) dataSource; md5 = image.getMd5(); @@ -139,15 +140,13 @@ public class CorrelationDataSource implements Serializable { sha256 = image.getSha256(); } } catch (TskDataException | TskCoreException ex) { - throw new CentralRepoException("Error getting data source info: " + ex.getMessage()); + throw new CentralRepoException("Error getting data source info from case database", ex); } correlationDataSource = new CorrelationDataSource(correlationCase, deviceId, dataSource.getName(), dataSource.getId(), md5, sha1, sha256); - if (useCR) { - //add the correlation data source to the central repository and fill in the Central repository data source id in the object - correlationDataSource = CentralRepository.getInstance().newDataSource(correlationDataSource); - } + correlationDataSource = CentralRepository.getInstance().newDataSource(correlationDataSource); } + return correlationDataSource; } @@ -205,66 +204,68 @@ public class CorrelationDataSource implements Serializable { public String getName() { return name; } - + /** * @return the MD5 hash value */ public String getMd5() { return (md5Hash == null ? "" : md5Hash); } - + /** - * Set the MD5 hash value and persist to the Central Repository if available. - * + * Set the MD5 hash value and persist to the Central Repository if + * available. + * * @param md5Hash The MD5 hash value. + * * @throws CentralRepoException If there's an issue updating the Central - Repository. + * Repository. */ public void setMd5(String md5Hash) throws CentralRepoException { this.md5Hash = md5Hash; - + if (dataSourceObjectID != -1) { CentralRepository.getInstance().updateDataSourceMd5Hash(this); } } - + /** * @return the SHA-1 hash value */ public String getSha1() { return (sha1Hash == null ? "" : sha1Hash); } - + /** * Set the SHA-1 hash value and persist to the Central Repository if * available. - * + * * @param sha1Hash The SHA-1 hash value. */ public void setSha1(String sha1Hash) throws CentralRepoException { this.sha1Hash = sha1Hash; - + if (dataSourceObjectID != -1) { CentralRepository.getInstance().updateDataSourceSha1Hash(this); } } - + /** * @return the SHA-256 hash value */ public String getSha256() { return (sha256Hash == null ? "" : sha256Hash); } - + /** * Set the SHA-256 hash value and persist to the Central Repository if * available. - * + * * @param sha256Hash The SHA-256 hash value. */ public void setSha256(String sha256Hash) throws CentralRepoException { this.sha256Hash = sha256Hash; - + if (dataSourceObjectID != -1) { CentralRepository.getInstance().updateDataSourceSha256Hash(this); } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED index f30a0b6309..de6d91c29f 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties-MERGED @@ -1,27 +1,29 @@ CentralRepoIngestModel_name_header=Name:
CentralRepoIngestModel_previous_case_header=
Previous Cases:
-CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Central Repository ingest module. -CentralRepoIngestModule.notfyBubble.title=Central Repository Not Initialized CentralRepoIngestModule.prevCaseComment.text=Previous Case: CentralRepoIngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository) +CentralRepoIngestModule_cannotGetCrCaseErrMsg=Case not present in the central repository +CentralRepoIngestModule_cannotGetCrDataSourceErrMsg=Data source not present in the central repository +CentralRepoIngestModule_crDatabaseTypeMismatch=Mulit-user cases require a PostgreSQL central repository +CentralRepoIngestModule_crInaccessibleErrMsg=Error accessing central repository +CentralRepoIngestModule_crNotEnabledErrMsg=Central repository required, but not enabled +CentralRepoIngestModule_missingFileCorrAttrTypeErrMsg=Correlation attribute type for files not found in the central repository +CentralRepoIngestModule_noCurrentCaseErrMsg=Error getting current case CentralRepoIngestModule_notable_message_header=A file in this data source was previously seen and tagged as Notable.
+# {0} - list of cases +CentralRepoIngestModule_notableJustification=Previously marked as notable in cases {0} +CentralRepoIngestModule_notableSetName=Previously Tagged As Notable (Central Repository) +CentralRepoIngestModule_osAcctMgrInaccessibleErrMsg=Error getting OS accounts manager # {0} - Name of file that is Notable CentralRepoIngestModule_postToBB_knownBadMsg=Notable: {0} +# {0} - list of cases +CentralRepoIngestModule_prevSeenJustification=Previously seen in cases {0} +CentralRepoIngestModule_prevSeenOsAcctConfig=Previously Seen Users (Central Repository) +CentralRepoIngestModule_prevSeenOsAcctSetName=Users seen in previous cases +CentralRepoIngestModule_prevSeenSetName=Previously Seen (Central Repository) +CentralRepoIngestModule_prevUnseenJustification=Previously seen in zero cases CentralRepoIngestModuleFactory.ingestmodule.desc=Saves properties to the central repository for later correlation CentralRepoIngestModuleFactory.ingestmodule.name=Central Repository -CrDataArtifactIngestModule_crInaccessibleErrMsg=Error accessing central repository -CrDataArtifactIngestModule_crNotEnabledErrMsg=Central repository required, but not enabled -CrDataArtifactIngestModule_noCurrentCaseErrMsg=Error getting current case -# {0} - list of cases -CrDataArtifactIngestModule_notableJustification=Previously marked as notable in cases {0} -CrDataArtifactIngestModule_notableSetName=Previously Tagged As Notable (Central Repository) -CrDataArtifactIngestModule_osAcctMgrInaccessibleErrMsg=Error getting OS accounts manager -# {0} - list of cases -CrDataArtifactIngestModule_prevSeenJustification=Previously seen in cases {0} -CrDataArtifactIngestModule_prevSeenOsAcctConfig=Previously Seen Users (Central Repository) -CrDataArtifactIngestModule_prevSeenOsAcctSetName=Users seen in previous cases -CrDataArtifactIngestModule_prevSeenSetName=Previously Seen (Central Repository) -CrDataArtifactIngestModule_prevUnseenJustification=Previously seen in zero cases IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=Flag devices and users previously seen in other cases diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/CentralRepoDataArtifactIngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/CentralRepoDataArtifactIngestModule.java index a44c33391a..f1610659f9 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/CentralRepoDataArtifactIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/CentralRepoDataArtifactIngestModule.java @@ -33,7 +33,9 @@ import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; @@ -103,16 +105,24 @@ public class CentralRepoDataArtifactIngestModule implements DataArtifactIngestMo } @NbBundle.Messages({ - "CrDataArtifactIngestModule_crNotEnabledErrMsg=Central repository required, but not enabled", - "CrDataArtifactIngestModule_noCurrentCaseErrMsg=Error getting current case", - "CrDataArtifactIngestModule_osAcctMgrInaccessibleErrMsg=Error getting OS accounts manager", - "CrDataArtifactIngestModule_crInaccessibleErrMsg=Error accessing central repository",}) + "CentralRepoIngestModule_crNotEnabledErrMsg=Central repository required, but not enabled", + "CentralRepoIngestModule_noCurrentCaseErrMsg=Error getting current case", + "CentralRepoIngestModule_osAcctMgrInaccessibleErrMsg=Error getting OS accounts manager", + "CentralRepoIngestModule_crInaccessibleErrMsg=Error accessing central repository", + "CentralRepoIngestModule_crDatabaseTypeMismatch=Mulit-user cases require a PostgreSQL central repository" + }) @Override public void startUp(IngestJobContext context) throws IngestModuleException { + /* + * IMPORTANT: Start up IngestModuleException messages are displayed to + * the user, if a user is present. Therefore, an exception to the policy + * that exception messages are not localized is appropriate here. Also, + * the exception messages should be user-friendly. + */ dataSource = context.getDataSource(); ingestJobId = context.getJobId(); if (!CentralRepository.isEnabled()) { - throw new IngestModuleException(Bundle.CrDataArtifactIngestModule_crNotEnabledErrMsg()); // May be displayed to user. + throw new IngestModuleException(Bundle.CentralRepoIngestModule_crNotEnabledErrMsg()); // May be displayed to user. } try { currentCase = Case.getCurrentCaseThrows(); @@ -121,12 +131,17 @@ public class CentralRepoDataArtifactIngestModule implements DataArtifactIngestMo osAccountMgr = tskCase.getOsAccountManager(); centralRepo = CentralRepository.getInstance(); } catch (NoCurrentCaseException ex) { - throw new IngestModuleException(Bundle.CrDataArtifactIngestModule_noCurrentCaseErrMsg(), ex); // May be displayed to user. + throw new IngestModuleException(Bundle.CentralRepoIngestModule_noCurrentCaseErrMsg(), ex); } catch (TskCoreException ex) { - throw new IngestModuleException(Bundle.CrDataArtifactIngestModule_osAcctMgrInaccessibleErrMsg(), ex); // May be displayed to user. + throw new IngestModuleException(Bundle.CentralRepoIngestModule_osAcctMgrInaccessibleErrMsg(), ex); } catch (CentralRepoException ex) { - throw new IngestModuleException(Bundle.CrDataArtifactIngestModule_crInaccessibleErrMsg(), ex); // May be displayed to user. + throw new IngestModuleException(Bundle.CentralRepoIngestModule_crInaccessibleErrMsg(), ex); } + // Don't allow sqlite central repo databases to be used for multi user cases + if ((currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) && (CentralRepoDbManager.getSavedDbChoice().getDbPlatform() == CentralRepoPlatforms.SQLITE)) { + throw new IngestModuleException(Bundle.CentralRepoIngestModule_crDatabaseTypeMismatch()); + } + } /** @@ -187,8 +202,8 @@ public class CentralRepoDataArtifactIngestModule implements DataArtifactIngestMo * accounts if they have been seen in other cases. */ @NbBundle.Messages({ - "CrDataArtifactIngestModule_prevSeenOsAcctSetName=Users seen in previous cases", - "CrDataArtifactIngestModule_prevSeenOsAcctConfig=Previously Seen Users (Central Repository)" + "CentralRepoIngestModule_prevSeenOsAcctSetName=Users seen in previous cases", + "CentralRepoIngestModule_prevSeenOsAcctConfig=Previously Seen Users (Central Repository)" }) private void analyzeOsAccounts() { try { @@ -360,14 +375,14 @@ public class CentralRepoDataArtifactIngestModule implements DataArtifactIngestMo * @param corrAttrValue The value of the matched correlation attribute. */ @NbBundle.Messages({ - "CrDataArtifactIngestModule_notableSetName=Previously Tagged As Notable (Central Repository)", + "CentralRepoIngestModule_notableSetName=Previously Tagged As Notable (Central Repository)", "# {0} - list of cases", - "CrDataArtifactIngestModule_notableJustification=Previously marked as notable in cases {0}" + "CentralRepoIngestModule_notableJustification=Previously marked as notable in cases {0}" }) private void makePrevNotableAnalysisResult(Content content, Set previousCases, CorrelationAttributeInstance.Type corrAttrType, String corrAttrValue) { String prevCases = previousCases.stream().collect(Collectors.joining(",")); - String justification = Bundle.CrDataArtifactIngestModule_notableJustification(prevCases); - Collection attributes = Arrays.asList(new BlackboardAttribute(TSK_SET_NAME, CentralRepoIngestModuleFactory.getModuleName(), Bundle.CrDataArtifactIngestModule_notableSetName()), + String justification = Bundle.CentralRepoIngestModule_notableJustification(prevCases); + Collection attributes = Arrays.asList(new BlackboardAttribute(TSK_SET_NAME, CentralRepoIngestModuleFactory.getModuleName(), Bundle.CentralRepoIngestModule_notableSetName()), new BlackboardAttribute(TSK_CORRELATION_TYPE, CentralRepoIngestModuleFactory.getModuleName(), corrAttrType.getDisplayName()), new BlackboardAttribute(TSK_CORRELATION_VALUE, CentralRepoIngestModuleFactory.getModuleName(), corrAttrValue), new BlackboardAttribute(TSK_OTHER_CASES, CentralRepoIngestModuleFactory.getModuleName(), prevCases)); @@ -385,17 +400,17 @@ public class CentralRepoDataArtifactIngestModule implements DataArtifactIngestMo * @param corrAttrValue The value of the matched correlation attribute. */ @NbBundle.Messages({ - "CrDataArtifactIngestModule_prevSeenSetName=Previously Seen (Central Repository)", + "CentralRepoIngestModule_prevSeenSetName=Previously Seen (Central Repository)", "# {0} - list of cases", - "CrDataArtifactIngestModule_prevSeenJustification=Previously seen in cases {0}" + "CentralRepoIngestModule_prevSeenJustification=Previously seen in cases {0}" }) private void makePrevSeenAnalysisResult(Content content, Set previousCases, CorrelationAttributeInstance.Type corrAttrType, String corrAttrValue) { Optional score = calculateScore(previousCases.size()); if (score.isPresent()) { String prevCases = previousCases.stream().collect(Collectors.joining(",")); - String justification = Bundle.CrDataArtifactIngestModule_prevSeenJustification(prevCases); + String justification = Bundle.CentralRepoIngestModule_prevSeenJustification(prevCases); Collection analysisResultAttributes = Arrays.asList( - new BlackboardAttribute(TSK_SET_NAME, CentralRepoIngestModuleFactory.getModuleName(), Bundle.CrDataArtifactIngestModule_prevSeenSetName()), + new BlackboardAttribute(TSK_SET_NAME, CentralRepoIngestModuleFactory.getModuleName(), Bundle.CentralRepoIngestModule_prevSeenSetName()), new BlackboardAttribute(TSK_CORRELATION_TYPE, CentralRepoIngestModuleFactory.getModuleName(), corrAttrType.getDisplayName()), new BlackboardAttribute(TSK_CORRELATION_VALUE, CentralRepoIngestModuleFactory.getModuleName(), corrAttrValue), new BlackboardAttribute(TSK_OTHER_CASES, CentralRepoIngestModuleFactory.getModuleName(), prevCases)); @@ -411,13 +426,13 @@ public class CentralRepoDataArtifactIngestModule implements DataArtifactIngestMo * @param corrAttrValue The value of the new correlation attribute. */ @NbBundle.Messages({ - "CrDataArtifactIngestModule_prevUnseenJustification=Previously seen in zero cases" + "CentralRepoIngestModule_prevUnseenJustification=Previously seen in zero cases" }) private void makePrevUnseenAnalysisResult(Content content, CorrelationAttributeInstance.Type corrAttrType, String corrAttrValue) { Collection attributesForNewArtifact = Arrays.asList( new BlackboardAttribute(TSK_CORRELATION_TYPE, CentralRepoIngestModuleFactory.getModuleName(), corrAttrType.getDisplayName()), new BlackboardAttribute(TSK_CORRELATION_VALUE, CentralRepoIngestModuleFactory.getModuleName(), corrAttrValue)); - makeAndPostAnalysisResult(content, BlackboardArtifact.Type.TSK_PREVIOUSLY_UNSEEN, attributesForNewArtifact, "", Score.SCORE_LIKELY_NOTABLE, Bundle.CrDataArtifactIngestModule_prevUnseenJustification()); + makeAndPostAnalysisResult(content, BlackboardArtifact.Type.TSK_PREVIOUSLY_UNSEEN, attributesForNewArtifact, "", Score.SCORE_LIKELY_NOTABLE, Bundle.CentralRepoIngestModule_prevUnseenJustification()); } /** @@ -437,8 +452,8 @@ public class CentralRepoDataArtifactIngestModule implements DataArtifactIngestMo score = Score.SCORE_NONE; } return Optional.ofNullable(score); - } - + } + /** * Makes a new analysis result of a given type for a content and posts it to * the blackboard. diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/CentralRepoFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/CentralRepoFileIngestModule.java index ab02f9d849..a6a8e54d62 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/CentralRepoFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/CentralRepoFileIngestModule.java @@ -32,11 +32,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager; -import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.healthmonitor.HealthMonitor; import org.sleuthkit.autopsy.healthmonitor.TimingMetric; import org.sleuthkit.autopsy.ingest.FileIngestModule; @@ -59,18 +55,18 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.datamodel.Score; /** - * Ingest module for inserting entries into the Central Repository database on - * ingest of a data source + * A file ingest module that adds correlation attributes for files to the + * central repository and makes previously notable analysis results based on + * previous occurences. */ @Messages({"CentralRepoIngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)", "CentralRepoIngestModule.prevCaseComment.text=Previous Case: "}) final class CentralRepoFileIngestModule implements FileIngestModule { - private final static Logger logger = Logger.getLogger(CentralRepoFileIngestModule.class.getName()); + private static final Logger logger = Logger.getLogger(CentralRepoFileIngestModule.class.getName()); private static final String MODULE_NAME = CentralRepoIngestModuleFactory.getModuleName(); private final IngestServices services = IngestServices.getInstance(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); - private static final IngestModuleReferenceCounter warningMsgRefCounter = new IngestModuleReferenceCounter(); private long jobId; private CorrelationCase centralRepoCase; private CorrelationDataSource centralRepoDataSource; @@ -78,11 +74,14 @@ final class CentralRepoFileIngestModule implements FileIngestModule { private final boolean flagTaggedNotableItems; private Blackboard blackboard; private final boolean createCorrelationProperties; + private CentralRepository centralRepoDb; /** - * Instantiate the Central Repository ingest module. + * Constructs a file ingest module that adds correlation attributes for + * files to the central repository and makes previously notable analysis + * results based on previous occurences. * - * @param settings The ingest settings for the module instance. + * @param settings The ingest job settings. */ CentralRepoFileIngestModule(IngestSettings settings) { flagTaggedNotableItems = settings.isFlagTaggedNotableItems(); @@ -91,22 +90,6 @@ final class CentralRepoFileIngestModule implements FileIngestModule { @Override public ProcessResult process(AbstractFile abstractFile) { - if (CentralRepository.isEnabled() == false) { - /* - * Not signaling an error for now. This is a workaround for the way - * all newly didscovered ingest modules are automatically anabled. - * - * TODO (JIRA-2731): Add isEnabled API for ingest modules. - */ - return ProcessResult.OK; - } - - try { - blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard(); - } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Exception while getting open case.", ex); - return ProcessResult.ERROR; - } if (!CorrelationAttributeUtil.isSupportedAbstractFileType(abstractFile)) { return ProcessResult.OK; @@ -116,15 +99,6 @@ final class CentralRepoFileIngestModule implements FileIngestModule { return ProcessResult.OK; } - CentralRepository dbManager; - try { - dbManager = CentralRepository.getInstance(); - } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); - return ProcessResult.ERROR; - } - - // only continue if we are correlating filesType if (!filesType.isEnabled()) { return ProcessResult.OK; } @@ -142,7 +116,7 @@ final class CentralRepoFileIngestModule implements FileIngestModule { if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) { try { TimingMetric timingMetric = HealthMonitor.getTimingMetric("Central Repository: Notable artifact query"); - List caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); + List caseDisplayNamesList = centralRepoDb.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); HealthMonitor.submitTimingMetric(timingMetric); if (!caseDisplayNamesList.isEmpty()) { postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList, filesType, md5); @@ -169,7 +143,7 @@ final class CentralRepoFileIngestModule implements FileIngestModule { TskData.FileKnown.UNKNOWN // NOTE: Known status in the CR is based on tagging, not hashes like the Case Database. , abstractFile.getId()); - dbManager.addAttributeInstanceBulk(cefi); + centralRepoDb.addAttributeInstanceBulk(cefi); } catch (CentralRepoException ex) { logger.log(Level.SEVERE, "Error adding artifact to bulk artifacts.", ex); // NON-NLS return ProcessResult.ERROR; @@ -183,113 +157,68 @@ final class CentralRepoFileIngestModule implements FileIngestModule { @Override public void shutDown() { - if ((CentralRepository.isEnabled() == false) || (centralRepoCase == null) || (centralRepoDataSource == null)) { - return; + if (refCounter.decrementAndGet(jobId) == 0) { + try { + centralRepoDb.commitAttributeInstancesBulk(); + } catch (CentralRepoException ex) { + logger.log(Level.SEVERE, "Error committing bulk insert of correlation attributes", ex); // NON-NLS + } } - CentralRepository dbManager; - try { - dbManager = CentralRepository.getInstance(); - } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); - return; - } - try { - dbManager.commitAttributeInstancesBulk(); - } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error doing bulk insert of artifacts.", ex); // NON-NLS - } - try { - Long count = dbManager.getCountArtifactInstancesByCaseDataSource(centralRepoDataSource); - logger.log(Level.INFO, "{0} artifacts in db for case: {1} ds:{2}", new Object[]{count, centralRepoCase.getDisplayName(), centralRepoDataSource.getName()}); // NON-NLS - } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error counting artifacts.", ex); // NON-NLS - } - - // TODO: once we implement shared cache, if refCounter is 1, then submit data in bulk. - refCounter.decrementAndGet(jobId); } - // see ArtifactManagerTimeTester for details @Messages({ - "CentralRepoIngestModule.notfyBubble.title=Central Repository Not Initialized", - "CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Central Repository ingest module." + "CentralRepoIngestModule_missingFileCorrAttrTypeErrMsg=Correlation attribute type for files not found in the central repository", + "CentralRepoIngestModule_cannotGetCrCaseErrMsg=Case not present in the central repository", + "CentralRepoIngestModule_cannotGetCrDataSourceErrMsg=Data source not present in the central repository" }) @Override public void startUp(IngestJobContext context) throws IngestModuleException { - if (CentralRepository.isEnabled() == false) { - /* - * Not throwing the customary exception for now. This is a - * workaround for the way all newly didscovered ingest modules are - * automatically anabled. - * - * TODO (JIRA-2731): Add isEnabled API for ingest modules. - */ - if (RuntimeProperties.runningWithGUI()) { - if (1L == warningMsgRefCounter.incrementAndGet(jobId)) { - MessageNotifyUtil.Notify.warn(Bundle.CentralRepoIngestModule_notfyBubble_title(), Bundle.CentralRepoIngestModule_errorMessage_isNotEnabled()); - } - } - return; + jobId = context.getJobId(); + + /* + * IMPORTANT: Start up IngestModuleException messages are displayed to + * the user, if a user is present. Therefore, an exception to the policy + * that exception messages are not localized is appropriate here. Also, + * the exception messages should be user-friendly. + */ + if (!CentralRepository.isEnabled()) { + throw new IngestModuleException(Bundle.CrDataArtifactIngestModule_crNotEnabledErrMsg()); } + Case autopsyCase; try { autopsyCase = Case.getCurrentCaseThrows(); } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Exception while getting open case.", ex); - throw new IngestModuleException("Exception while getting open case.", ex); + throw new IngestModuleException(Bundle.CrDataArtifactIngestModule_noCurrentCaseErrMsg(), ex); } - // Don't allow sqlite central repo databases to be used for multi user cases - if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) - && (CentralRepoDbManager.getSavedDbChoice().getDbPlatform() == CentralRepoPlatforms.SQLITE)) { - logger.log(Level.SEVERE, "Cannot run Central Repository ingest module on a multi-user case with a SQLite central repository."); - throw new IngestModuleException("Cannot run on a multi-user case with a SQLite central repository."); // NON-NLS - } - jobId = context.getJobId(); + blackboard = autopsyCase.getSleuthkitCase().getBlackboard(); - CentralRepository centralRepoDb; try { centralRepoDb = CentralRepository.getInstance(); } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error connecting to central repository database.", ex); // NON-NLS - throw new IngestModuleException("Error connecting to central repository database.", ex); // NON-NLS + throw new IngestModuleException(Bundle.CentralRepoIngestModule_crInaccessibleErrMsg(), ex); } try { filesType = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS - throw new IngestModuleException("Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS + throw new IngestModuleException(Bundle.CentralRepoIngestModule_missingFileCorrAttrTypeErrMsg(), ex); } try { centralRepoCase = centralRepoDb.getCase(autopsyCase); } catch (CentralRepoException ex) { - throw new IngestModuleException("Unable to get case from central repository database ", ex); + throw new IngestModuleException(Bundle.CentralRepoIngestModule_cannotGetCrCaseErrMsg(), ex); } try { centralRepoDataSource = CorrelationDataSource.fromTSKDataSource(centralRepoCase, context.getDataSource()); } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error getting data source info.", ex); // NON-NLS - throw new IngestModuleException("Error getting data source info.", ex); // NON-NLS + throw new IngestModuleException(Bundle.CentralRepoIngestModule_cannotGetCrDataSourceErrMsg(), ex); } - // TODO: once we implement a shared cache, load/init it here w/ syncronized and define reference counter - // if we are the first thread / module for this job, then make sure the case - // and image exist in the DB before we associate artifacts with it. - if (refCounter.incrementAndGet(jobId) - == 1) { - // ensure we have this data source in the EAM DB - try { - if (null == centralRepoDb.getDataSource(centralRepoCase, centralRepoDataSource.getDataSourceObjectID())) { - centralRepoDb.newDataSource(centralRepoDataSource); - } - } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error adding data source to Central Repository.", ex); // NON-NLS - throw new IngestModuleException("Error adding data source to Central Repository.", ex); // NON-NLS - } - } + refCounter.incrementAndGet(jobId); } /** @@ -298,19 +227,18 @@ final class CentralRepoFileIngestModule implements FileIngestModule { * @param abstractFile The file from which to create an artifact. * @param caseDisplayNames Case names to be added to a TSK_COMMON attribute. */ - private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List caseDisplayNames, CorrelationAttributeInstance.Type aType, String value) { + private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List caseDisplayNames, CorrelationAttributeInstance.Type corrAtrrType, String corrAttrValue) { String prevCases = caseDisplayNames.stream().distinct().collect(Collectors.joining(",")); String justification = "Previously marked as notable in cases " + prevCases; - Collection attributes = Arrays.asList( - new BlackboardAttribute( - TSK_SET_NAME, MODULE_NAME, - Bundle.CentralRepoIngestModule_prevTaggedSet_text()), + Collection attributes = Arrays.asList(new BlackboardAttribute( + TSK_SET_NAME, MODULE_NAME, + Bundle.CentralRepoIngestModule_prevTaggedSet_text()), new BlackboardAttribute( TSK_CORRELATION_TYPE, MODULE_NAME, - aType.getDisplayName()), + corrAtrrType.getDisplayName()), new BlackboardAttribute( TSK_CORRELATION_VALUE, MODULE_NAME, - value), + corrAttrValue), new BlackboardAttribute( TSK_OTHER_CASES, MODULE_NAME, prevCases)); @@ -336,14 +264,6 @@ final class CentralRepoFileIngestModule implements FileIngestModule { } } - @Messages({ - "CentralRepoIngestModule_notable_message_header=A file in this data source was previously seen and tagged as Notable.
", - "CentralRepoIngestModel_name_header=Name:
", - "CentralRepoIngestModel_previous_case_header=
Previous Cases:
", - "# {0} - Name of file that is Notable", - "CentralRepoIngestModule_postToBB_knownBadMsg=Notable: {0}" - }) - /** * Post a message to the ingest inbox alerting the user that a bad file was * found. @@ -353,6 +273,13 @@ final class CentralRepoFileIngestModule implements FileIngestModule { * @param md5Hash badFile's md5 hash * @param caseDisplayNames List of cases that the artifact appears in. */ + @Messages({ + "CentralRepoIngestModule_notable_message_header=A file in this data source was previously seen and tagged as Notable.
", + "CentralRepoIngestModel_name_header=Name:
", + "CentralRepoIngestModel_previous_case_header=
Previous Cases:
", + "# {0} - Name of file that is Notable", + "CentralRepoIngestModule_postToBB_knownBadMsg=Notable: {0}" + }) private void sendBadFileInboxMessage(BlackboardArtifact artifact, String name, String md5Hash, List caseDisplayNames) { StringBuilder detailsSb = new StringBuilder(1024); @@ -368,4 +295,5 @@ final class CentralRepoFileIngestModule implements FileIngestModule { name + md5Hash, artifact)); } + }