diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index dae8bbe312..5f47487f94 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -61,10 +61,10 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { */ public AddEditCentralRepoCommentAction(AbstractFile file) { fileId = file.getId(); - correlationAttributeInstance = CorrelationAttributeUtil.getInstanceFromContent(file); + correlationAttributeInstance = CorrelationAttributeUtil.getCorrAttrForFile(file); if (correlationAttributeInstance == null) { addToDatabase = true; - correlationAttributeInstance = CorrelationAttributeUtil.makeInstanceFromContent(file); + correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttrFromFile(file); } if (file.getSize() == 0) { putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoCommentEmptyFile()); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index a28a013220..881e60236e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2017-2019 Basis Technology Corp. + * Copyright 2017-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -464,7 +464,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // correlate on blackboard artifact attributes if they exist and supported BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node); if (bbArtifact != null && CentralRepository.isEnabled()) { - ret.addAll(CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbArtifact, false)); + ret.addAll(CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact)); } // we can correlate based on the MD5 if it is enabled diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index 07eb454ac5..814169ef85 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2020 Basis Technology Corp. + * Copyright 2017-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,176 +30,280 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; /** - * Utility class for correlation attributes in the central repository + * Utility class for working with correlation attributes in the central + * repository. */ public class CorrelationAttributeUtil { private static final Logger logger = Logger.getLogger(CorrelationAttributeUtil.class.getName()); - @Messages({"EamArtifactUtil.emailaddresses.text=Email Addresses"}) - public static String getEmailAddressAttrString() { - return Bundle.EamArtifactUtil_emailaddresses_text(); + /** + * Gets a string that is expected to be the same string that is stored in + * the correlation_types table in the central repository as the display name + * for the email address correlation attribute type. This string is + * duplicated in the CorrelationAttributeInstance class. + * + * TODO (Jira-6088): We should not have multiple deifnitions of this string. + * + * @return The display name of the email address correlation attribute type. + */ + @Messages({"CorrelationAttributeUtil.emailaddresses.text=Email Addresses"}) + private static String getEmailAddressAttrDisplayName() { + return Bundle.CorrelationAttributeUtil_emailaddresses_text(); } /** - * Static factory method to examine a BlackboardArtifact to determine if it - * has contents that can be used for Correlation. If so, return a - * EamArtifact with a single EamArtifactInstance within. If not, return - * null. + * Makes zero to many correlation attribute instances from the attributes of + * an artifact. * - * @param artifact BlackboardArtifact to examine - * @param checkEnabled If true, only create a CorrelationAttribute if it is - * enabled + * IMPORTANT: The correlation attribute instances are NOT added to the + * central repository by this method. * - * @return List of EamArtifacts + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. + * + * @param artifact An artifact. + * + * @return A list, possibly empty, of correlation attribute instances for + * the artifact. */ - public static List makeInstancesFromBlackboardArtifact(BlackboardArtifact artifact, - boolean checkEnabled) { - List eamArtifacts = new ArrayList<>(); + public static List makeCorrAttrsFromArtifact(BlackboardArtifact artifact) { + List correlationAttrs = new ArrayList<>(); try { - BlackboardArtifact artifactForInstance = null; - if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) { - // Get the associated artifactForInstance - BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); - if (attribute != null) { - artifactForInstance = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong()); - } - } else { - artifactForInstance = artifact; - } - if (artifactForInstance != null) { - int artifactTypeID = artifactForInstance.getArtifactTypeID(); + BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact); + if (sourceArtifact != null) { + int artifactTypeID = sourceArtifact.getArtifactTypeID(); if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - BlackboardAttribute setNameAttr = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); - if (setNameAttr != null - && CorrelationAttributeUtil.getEmailAddressAttrString().equals(setNameAttr.getValueString())) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); + BlackboardAttribute setNameAttr = sourceArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME)); + if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) { + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID); } + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) { + makeCorrAttrFromArtifactPhoneAttr(sourceArtifact); - String value = null; - if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { - value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); - } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { - value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); - } else if (null != artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { - value = artifactForInstance.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); - } - // Remove all non-numeric symbols to semi-normalize phone numbers, preserving leading "+" character - if (value != null) { - String newValue = value.replaceAll("\\D", ""); - if (value.startsWith("+")) { - newValue = "+" + newValue; - } - value = newValue; - // Only add the correlation attribute if the resulting phone number large enough to be of use - // (these 3-5 digit numbers can be valid, but are not useful for correlation) - if (value.length() > 5) { - CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artifactForInstance, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); - if (inst != null) { - eamArtifacts.add(inst); - } - } - } } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID); + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) { - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID); - addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID); + makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID); + + } else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { + makeCorrAttrFromAcctArtifact(correlationAttrs, sourceArtifact); } } } catch (CentralRepoException ex) { - logger.log(Level.SEVERE, "Error getting defined correlation types.", ex); // NON-NLS - return eamArtifacts; + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", artifact), ex); // NON-NLS + return correlationAttrs; } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS - return null; + logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", artifact), ex); // NON-NLS + return correlationAttrs; } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS - return null; + logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS + return correlationAttrs; } - return eamArtifacts; + return correlationAttrs; } /** - * Add a CorrelationAttributeInstance of the specified type to the provided - * list if the artifactForInstance has an Attribute of the given type with a - * non empty value. + * Gets the associated artifact of a "meta-artifact" such as an interesting + * artifact hit artifact. * - * @param eamArtifacts the list of CorrelationAttributeInstance objects - * which should be added to - * @param artifact the blackboard artifactForInstance which we are - * creating a CorrelationAttributeInstance for - * @param bbAttributeType the type of BlackboardAttribute we expect to exist - * for a CorrelationAttributeInstance of this type - * generated from this Blackboard Artifact - * @param typeId the integer type id of the - * CorrelationAttributeInstance type + * @param artifact An artifact. * - * @throws CentralRepoException - * @throws TskCoreException + * @return The associated artifact if the input artifact is a + * "meta-artifact", otherwise the input artifact. + * + * @throws NoCurrentCaseException If there is no open case. + * @throws TskCoreException If there is an error querying thew case + * database. */ - private static void addCorrelationAttributeToList(List eamArtifacts, BlackboardArtifact artifact, ATTRIBUTE_TYPE bbAttributeType, int typeId) throws CentralRepoException, TskCoreException { - BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(bbAttributeType)); + private static BlackboardArtifact getCorrAttrSourceArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException { + BlackboardArtifact sourceArtifact = null; + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) { + BlackboardAttribute assocArtifactAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); + if (assocArtifactAttr != null) { + sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong()); + } + } else { + sourceArtifact = artifact; + } + return sourceArtifact; + } + + /** + * Makes a correlation attribute instance from a phone number attribute of an + * artifact. + * + * @param artifact An artifact with a phone number attribute. + * + * @return The correlation instance artifact or null, if the phone number is + * not a valid correlation attribute. + * + * @throws TskCoreException If there is an error querying the case + * database. + * @throws CentralRepoException If there is an error querying the central + * repository. + */ + private static CorrelationAttributeInstance makeCorrAttrFromArtifactPhoneAttr(BlackboardArtifact artifact) throws TskCoreException, CentralRepoException { + CorrelationAttributeInstance corrAttr = null; + + /* + * Extract the phone number from the artifact attribute. + */ + String value = null; + if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) { + value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString(); + } else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) { + value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString(); + } else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) { + value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); + } + + /* + * Normalize the phone number. + */ + if (value != null) { + String newValue = value.replaceAll("\\D", ""); + if (value.startsWith("+")) { + newValue = "+" + newValue; + } + value = newValue; + + /* + * Validate the phone number. Three to five digit phone numbers may + * be valid, but they are too short to use as correlation + * attributes. + */ + if (value.length() > 5) { + corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value); + } + } + + return corrAttr; + } + + /** + * Makes a correlation attribute instance for an account artifact. + * + * IMPORTANT: The correlation attribute instance is NOT added to the central + * repository by this method. + * + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. + * + * @param corrAttrInstances A list of correlation attribute instances. + * @param acctArtifact An account artifact. + * + * @return The correlation attribute instance. + */ + private static void makeCorrAttrFromAcctArtifact(List corrAttrInstances, BlackboardArtifact acctArtifact) { + // RAMAN TODO: Convert TSK_ACCOUNT_TYPE attribute to correlation attribute type + // RAMAN TODO: Extract TSK_ID as value +// CorrelationAttributeInstance corrAttr = makeCorrAttr(acctArtifact, corrType, corrAttrValue); +// if (corrAttr != null) { +// corrAttrInstances.add(corrAttr); +// } + } + + /** + * Makes a correlation attribute instance from a specified attribute of an + * artifact. The correlation attribute instance is added to an input list. + * + * @param corrAttrInstances A list of correlation attribute instances. + * @param artifact An artifact. + * @param artAttrType The type of the atrribute of the artifact that + * is to be made into a correlatin attribute + * instance. + * @param typeId The type ID for the desired correlation + * attribute instance. + * + * @throws CentralRepoException If there is an error querying the central + * repository. + * @throws TskCoreException If there is an error querying the case + * database. + */ + private static void makeCorrAttrFromArtifactAttr(List corrAttrInstances, BlackboardArtifact artifact, ATTRIBUTE_TYPE artAttrType, int typeId) throws CentralRepoException, TskCoreException { + BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(artAttrType)); if (attribute != null) { String value = attribute.getValueString(); if ((null != value) && (value.isEmpty() == false)) { - CorrelationAttributeInstance inst = makeCorrelationAttributeInstanceUsingTypeValue(artifact, CentralRepository.getInstance().getCorrelationTypeById(typeId), value); + CorrelationAttributeInstance inst = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(typeId), value); if (inst != null) { - eamArtifacts.add(inst); + corrAttrInstances.add(inst); } } } } /** - * Uses the determined type and vallue, then looks up instance details to - * create proper CorrelationAttributeInstance. + * Makes a correlation attribute instance of a given type from an artifact. * - * @param bbArtifact the blackboard artifactForInstance - * @param correlationType the given type - * @param value the artifactForInstance value + * @param artifact The artifact. + * @param correlationType the correlation attribute type. + * @param value The correlation attribute value. * - * @return CorrelationAttributeInstance from details, or null if validation - * failed or another error occurred + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. + * + * @return The correlation attribute instance or null, if an error occurred. */ - private static CorrelationAttributeInstance makeCorrelationAttributeInstanceUsingTypeValue(BlackboardArtifact bbArtifact, CorrelationAttributeInstance.Type correlationType, String value) { + private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value) { try { Case currentCase = Case.getCurrentCaseThrows(); - AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID()); + AbstractFile bbSourceFile = currentCase.getSleuthkitCase().getAbstractFileById(artifact.getObjectID()); if (null == bbSourceFile) { logger.log(Level.SEVERE, "Error creating artifact instance. Abstract File was null."); // NON-NLS return null; } - // make an instance for the BB source file CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); return new CorrelationAttributeInstance( correlationType, @@ -212,31 +316,34 @@ public class CorrelationAttributeUtil { bbSourceFile.getId()); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting AbstractFile for artifact: " + bbArtifact.toString(), ex); // NON-NLS + logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", artifact), ex); // NON-NLS return null; } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { - logger.log(Level.WARNING, "Error creating artifact instance for artifact: " + bbArtifact.toString(), ex); // NON-NLS + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", artifact), ex); // NON-NLS return null; } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS return null; } } /** - * Retrieve CorrelationAttribute from the given Content. + * Gets the correlation attribute instance for a file. * - * @param content The content object + * @param file The file. * - * @return The new CorrelationAttribute, or null if retrieval failed. + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. + * + * @return The correlation attribute instance or null, if no such + * correlation attribute instance was found or an error occurred. */ - public static CorrelationAttributeInstance getInstanceFromContent(Content content) { - - if (!(content instanceof AbstractFile)) { - return null; - } - - final AbstractFile file = (AbstractFile) content; + public static CorrelationAttributeInstance getCorrAttrForFile(AbstractFile file) { if (!isSupportedAbstractFileType(file)) { return null; @@ -254,11 +361,14 @@ public class CorrelationAttributeUtil { return null; } correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource()); - } catch (TskCoreException | CentralRepoException ex) { - logger.log(Level.SEVERE, "Error retrieving correlation attribute.", ex); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error getting querying case database (%s)", file), ex); // NON-NLS + return null; + } catch (CentralRepoException ex) { + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS return null; } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Case is closed.", ex); + logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS return null; } @@ -266,20 +376,22 @@ public class CorrelationAttributeUtil { try { correlationAttributeInstance = CentralRepository.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, file.getId()); } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { - logger.log(Level.WARNING, String.format( - "Correlation attribute could not be retrieved for '%s' (id=%d): ", - content.getName(), content.getId()), ex); + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS return null; } - //if there was no correlation attribute found for the item using object_id then check for attributes added with schema 1,1 which lack object_id + + /* + * If no correlation attribute instance was found when querying by file + * object ID, try searching by file path instead. This is necessary + * because file object IDs were not stored in the central repository in + * early versions of its schema. + */ if (correlationAttributeInstance == null && file.getMd5Hash() != null) { String filePath = (file.getParentPath() + file.getName()).toLowerCase(); try { correlationAttributeInstance = CentralRepository.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, file.getMd5Hash(), filePath); } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { - logger.log(Level.WARNING, String.format( - "Correlation attribute could not be retrieved for '%s' (id=%d): ", - content.getName(), content.getId()), ex); + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS return null; } } @@ -288,32 +400,31 @@ public class CorrelationAttributeUtil { } /** - * Create an EamArtifact from the given Content. Will return null if an - * artifactForInstance can not be created - this is not necessarily an error - * case, it just means an artifactForInstance can't be made. If creation - * fails due to an error (and not that the file is the wrong type or it has - * no hash), the error will be logged before returning. + * Makes a correlation attribute instance for a file. * - * Does not add the artifactForInstance to the database. + * IMPORTANT: The correlation attribute instance is NOT added to the central + * repository by this method. * - * @param content The content object + * TODO (Jira-6088): The methods in this low-level, utility class should + * throw exceptions instead of logging them. The reason for this is that the + * clients of the utility class, not the utility class itself, should be in + * charge of error handling policy, per the Autopsy Coding Standard. Note + * that clients of several of these methods currently cannot determine + * whether receiving a null return value is an error or not, plus null + * checking is easy to forget, while catching exceptions is enforced. * - * @return The new EamArtifact or null if creation failed + * @param file The file. + * + * @return The correlation attribute instance or null, if an error occurred. */ - public static CorrelationAttributeInstance makeInstanceFromContent(Content content) { + public static CorrelationAttributeInstance makeCorrAttrFromFile(AbstractFile file) { - if (!(content instanceof AbstractFile)) { + if (!isSupportedAbstractFileType(file)) { return null; } - final AbstractFile af = (AbstractFile) content; - - if (!isSupportedAbstractFileType(af)) { - return null; - } - - // We need a hash to make the artifactForInstance - String md5 = af.getMd5Hash(); + // We need a hash to make the correlation artifact instance. + String md5 = file.getMd5Hash(); if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) { return null; } @@ -324,31 +435,33 @@ public class CorrelationAttributeUtil { CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); return new CorrelationAttributeInstance( filesType, - af.getMd5Hash(), + file.getMd5Hash(), correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, af.getDataSource()), - af.getParentPath() + af.getName(), + CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource()), + file.getParentPath() + file.getName(), "", TskData.FileKnown.UNKNOWN, - af.getId()); + file.getId()); - } catch (TskCoreException | CentralRepoException | CorrelationAttributeNormalizationException ex) { - logger.log(Level.SEVERE, "Error making correlation attribute.", ex); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error querying case database (%s)", file), ex); // NON-NLS + return null; + } catch (CentralRepoException | CorrelationAttributeNormalizationException ex) { + logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS return null; } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Case is closed.", ex); + logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS return null; } } /** - * Check whether the given abstract file should be processed for the central - * repository. + * Checks whether or not a file is of a type that can be added to the + * central repository as a correlation attribute instance. * - * @param file The file to test + * @param file A file. * - * @return true if the file should be added to the central repo, false - * otherwise + * @return True or false. */ public static boolean isSupportedAbstractFileType(AbstractFile file) { if (file == null) { @@ -375,9 +488,9 @@ public class CorrelationAttributeUtil { } /** - * Constructs a new EamArtifactUtil + * Prevent instantiation of this utility class. */ private CorrelationAttributeUtil() { - //empty constructor } + } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index c5f6ebdbe2..1df0e10dc6 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2018 Basis Technology Corp. + * Copyright 2017-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -52,7 +52,6 @@ import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; /** @@ -197,7 +196,7 @@ final class CaseEventListener implements PropertyChangeListener { } } - final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeInstanceFromContent(af); + final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile(af); if (eamArtifact != null) { // send update to Central Repository db @@ -297,7 +296,7 @@ final class CaseEventListener implements PropertyChangeListener { return; } - List convertedArtifacts = CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbArtifact, true); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { eamArtifact.setComment(comment); try { @@ -370,7 +369,7 @@ final class CaseEventListener implements PropertyChangeListener { if (!hasTagWithConflictingKnownStatus) { //Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed //with the initial set of correlation attributes this should be a single correlation attribute - List convertedArtifacts = CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbTag.getArtifact(), true); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbTag.getArtifact()); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); } @@ -406,9 +405,12 @@ 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) { - final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeInstanceFromContent(contentTag.getContent()); - if (eamArtifact != null) { - CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); + Content taggedContent = contentTag.getContent(); + if (taggedContent instanceof AbstractFile) { + final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile((AbstractFile)taggedContent); + if (eamArtifact != null) { + CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); + } } } } @@ -455,7 +457,7 @@ final class CaseEventListener implements PropertyChangeListener { } } catch (CentralRepoException ex) { LOGGER.log(Level.SEVERE, "Error adding new data source to the central repository", ex); //NON-NLS - } + } } // DATA_SOURCE_ADDED } @@ -495,7 +497,7 @@ final class CaseEventListener implements PropertyChangeListener { } } // CURRENT_CASE } - + private final class DataSourceNameChangedTask implements Runnable { private final CentralRepository dbManager; @@ -508,12 +510,12 @@ final class CaseEventListener implements PropertyChangeListener { @Override public void run() { - + final DataSourceNameChangedEvent dataSourceNameChangedEvent = (DataSourceNameChangedEvent) event; Content dataSource = dataSourceNameChangedEvent.getDataSource(); String newName = (String) event.getNewValue(); - - if (! StringUtils.isEmpty(newName)) { + + if (!StringUtils.isEmpty(newName)) { if (!CentralRepository.isEnabled()) { return; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 803f20b8c4..e79f339c70 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2019 Basis Technology Corp. + * Copyright 2017-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -456,7 +456,7 @@ public class IngestEventsListener { for (BlackboardArtifact bbArtifact : bbArtifacts) { // eamArtifact will be null OR a EamArtifact containing one EamArtifactInstance. - List convertedArtifacts = CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbArtifact, true); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { try { // Only do something with this artifact if it's unique within the job diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java index 9116ff9b45..3c967db3fd 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -198,7 +198,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data startSection(html, "Central Repository Comments"); List instancesList = new ArrayList<>(); if (artifact != null) { - instancesList.addAll(CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(artifact, false)); + instancesList.addAll(CorrelationAttributeUtil.makeCorrAttrsFromArtifact(artifact)); } try { List artifactTypes = CentralRepository.getInstance().getDefinedCorrelationTypes(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 9bb2f8c358..a60964aa19 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2012-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -549,7 +549,7 @@ public abstract class AbstractAbstractFileNode extends A protected CorrelationAttributeInstance getCorrelationAttributeInstance() { CorrelationAttributeInstance attribute = null; if (CentralRepository.isEnabled() && !UserPreferences.getHideSCOColumns()) { - attribute = CorrelationAttributeUtil.getInstanceFromContent(content); + attribute = CorrelationAttributeUtil.getCorrAttrForFile(content); } return attribute; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 7c2b8c92ad..b58bb915d0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2012-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -605,8 +605,8 @@ public class BlackboardArtifactNode extends AbstractContentNode listOfPossibleAttributes = CorrelationAttributeUtil.makeInstancesFromBlackboardArtifact(bbArtifact, false); + List listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact); if (listOfPossibleAttributes.size() > 1) { //Don't display anything if there is more than 1 correlation property for an artifact but let the user know description = Bundle.GetSCOTask_occurrences_multipleProperties();