diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index ceb0d9c3e7..182b92a661 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -345,6 +345,7 @@ org.sleuthkit.autopsy.report org.sleuthkit.autopsy.textextractors org.sleuthkit.autopsy.textextractors.configs + org.sleuthkit.autopsy.textsummarizer org.sleuthkit.autopsy.texttranslation org.sleuthkit.datamodel org.sleuthkit.datamodel.blackboardutils @@ -806,7 +807,7 @@ ext/jutf7-1.0.0.jar release/modules/ext/jutf7-1.0.0.jar - + ext/DatCon.jar release/modules/ext/DatCon.jar 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/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED index 9b43833ee2..345d5a420e 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED @@ -7,8 +7,10 @@ AbstractSqlEamDb.cannotUpgrage.message=Currently selected database platform "{0} AbstractSqlEamDb.failedToReadMajorVersion.message=Failed to read schema version for Central Repository. AbstractSqlEamDb.failedToReadMinorVersion.message=Failed to read schema minor version for Central Repository. AbstractSqlEamDb.upgradeSchema.incompatible=The selected Central Repository is not compatible with the current version of the application, please upgrade the application if you wish to use this Central Repository. +CentralRepoDbManager.connectionErrorMsg.text=Failed to connect to central repository database. CorrelationAttributeInstance.invalidName.message=Invalid database table name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'. CorrelationAttributeInstance.nullName.message=Database name is null. +CorrelationAttributeUtil.emailaddresses.text=Email Addresses CorrelationType.DOMAIN.displayName=Domains CorrelationType.EMAIL.displayName=Email Addresses CorrelationType.FILES.displayName=Files @@ -23,7 +25,6 @@ DataSourceUpdateService.serviceName.text=Update Central Repository Data Sources EamArtifactInstances.knownStatus.bad=Bad EamArtifactInstances.knownStatus.known=Known EamArtifactInstances.knownStatus.unknown=Unknown -EamArtifactUtil.emailaddresses.text=Email Addresses EamCase.title.caseDisplayName=Case Name: EamCase.title.caseNumber=Case Number: EamCase.title.caseUUID=Case UUID: diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java index 3e7ac158a9..fe54161762 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java @@ -802,5 +802,14 @@ public interface CentralRepository { * * @throws CentralRepoException */ - public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException; + public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException; + + + /** + * Returns list of all correlation types. + * + * @return list of Correlation types + * @throws CentralRepoException + */ + List getCorrelationTypes() throws CentralRepoException; } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java index f13b27787d..a8974f8e5a 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2018 Basis Technology Corp. + * Copyright 2015-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,7 @@ import java.util.List; import java.util.Objects; import java.util.regex.Pattern; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.TskData; /** @@ -220,6 +221,9 @@ public class CorrelationAttributeInstance implements Serializable { public static final int IMEI_TYPE_ID = 7; public static final int IMSI_TYPE_ID = 8; public static final int ICCID_TYPE_ID = 9; + + // An offset to assign Ids for additional correlation types. + public static final int ADDITIONAL_TYPES_BASE_ID = 1000; /** * Load the default correlation types @@ -238,18 +242,30 @@ public class CorrelationAttributeInstance implements Serializable { "CorrelationType.IMSI.displayName=IMSI Number", "CorrelationType.ICCID.displayName=ICCID Number"}) public static List getDefaultCorrelationTypes() throws CentralRepoException { - List DEFAULT_CORRELATION_TYPES = new ArrayList<>(); - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(FILES_TYPE_ID, Bundle.CorrelationType_FILES_displayName(), "file", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(DOMAIN_TYPE_ID, Bundle.CorrelationType_DOMAIN_displayName(), "domain", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(EMAIL_TYPE_ID, Bundle.CorrelationType_EMAIL_displayName(), "email_address", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(PHONE_TYPE_ID, Bundle.CorrelationType_PHONE_displayName(), "phone_number", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(USBID_TYPE_ID, Bundle.CorrelationType_USBID_displayName(), "usb_devices", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(SSID_TYPE_ID, Bundle.CorrelationType_SSID_displayName(), "wireless_networks", true, true)); // NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(MAC_TYPE_ID, Bundle.CorrelationType_MAC_displayName(), "mac_address", true, true)); //NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(IMEI_TYPE_ID, Bundle.CorrelationType_IMEI_displayName(), "imei_number", true, true)); //NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(IMSI_TYPE_ID, Bundle.CorrelationType_IMSI_displayName(), "imsi_number", true, true)); //NON-NLS - DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(ICCID_TYPE_ID, Bundle.CorrelationType_ICCID_displayName(), "iccid_number", true, true)); //NON-NLS - return DEFAULT_CORRELATION_TYPES; + List defaultCorrelationTypes = new ArrayList<>(); + + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(FILES_TYPE_ID, Bundle.CorrelationType_FILES_displayName(), "file", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(DOMAIN_TYPE_ID, Bundle.CorrelationType_DOMAIN_displayName(), "domain", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(EMAIL_TYPE_ID, Bundle.CorrelationType_EMAIL_displayName(), "email_address", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(PHONE_TYPE_ID, Bundle.CorrelationType_PHONE_displayName(), "phone_number", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(USBID_TYPE_ID, Bundle.CorrelationType_USBID_displayName(), "usb_devices", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(SSID_TYPE_ID, Bundle.CorrelationType_SSID_displayName(), "wireless_networks", true, true)); // NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(MAC_TYPE_ID, Bundle.CorrelationType_MAC_displayName(), "mac_address", true, true)); //NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(IMEI_TYPE_ID, Bundle.CorrelationType_IMEI_displayName(), "imei_number", true, true)); //NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(IMSI_TYPE_ID, Bundle.CorrelationType_IMSI_displayName(), "imsi_number", true, true)); //NON-NLS + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(ICCID_TYPE_ID, Bundle.CorrelationType_ICCID_displayName(), "iccid_number", true, true)); //NON-NLS + + // Create Correlation Types for Accounts. + int correlationTypeId = ADDITIONAL_TYPES_BASE_ID; + for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) { + // Skip Phone and Email accounts as there are already Correlation types defined for those. + if (type != Account.Type.EMAIL && type != Account.Type.PHONE) { + defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(correlationTypeId, type.getDisplayName(), type.getTypeName().toLowerCase(), true, true)); //NON-NLS + correlationTypeId++; + } + } + + return defaultCorrelationTypes; } /** 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/datamodel/Persona.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java new file mode 100644 index 0000000000..5fc458353b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java @@ -0,0 +1,87 @@ +/* + * Central Repository + * + * Copyright 2020 Basis Technology Corp. + * Contact: carrier sleuthkit 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.datamodel; + +/** + * This class abstracts a persona. + * + * An examiner may create a persona from an account. + * + */ +class Persona { + + /** + * Defines level of confidence in assigning a persona to an account. + */ + public enum Confidence { + UNKNOWN(1, "Unknown"), + LOW(2, "Low confidence"), + MEDIUM(3, "Medium confidence"), + HIGH(4, "High confidence"), + DERIVED(5, "Derived directly"); + + private final String name; + private final int level_id; + + Confidence(int level, String name) { + this.name = name; + this.level_id = level; + + } + + @Override + public String toString() { + return name; + } + + public int getLevel() { + return this.level_id; + } + } + + /** + * Defines status of a persona. + */ + public enum PersonaStatus { + + UNKNOWN(1, "Unknown"), + ACTIVE(2, "Active"), + MERGED(3, "Merged"), + SPLIT(4, "Split"), + DELETED(5, "Deleted"); + + private final String description; + private final int status_id; + + PersonaStatus(int status, String description) { + this.status_id = status; + this.description = description; + } + + @Override + public String toString() { + return description; + } + + public int getStatus() { + return this.status_id; + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java index 513fd3f944..abbae1c867 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java @@ -1373,6 +1373,9 @@ abstract class RdbmsCentralRepo implements CentralRepository { } synchronized (bulkArtifacts) { + if (bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())) == null) { + bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()), new ArrayList<>()); + } bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact); bulkArtifactsCount++; @@ -2845,6 +2848,7 @@ abstract class RdbmsCentralRepo implements CentralRepository { typeId = newCorrelationTypeKnownId(newType); } + typeCache.put(newType.getId(), newType); return typeId; } @@ -3105,6 +3109,45 @@ abstract class RdbmsCentralRepo implements CentralRepository { } } + /** + * Returns a list of all correlation types. It uses the cache to build the + * list. If the cache is empty, it reads from the database and loads up the + * cache. + * + * @return List of correlation types. + * @throws CentralRepoException + */ + @Override + public List getCorrelationTypes() throws CentralRepoException { + + if (typeCache.size() == 0) { + getCorrelationTypesFromCr(); + } + + return new ArrayList<>(typeCache.asMap().values()); + } + + /** + * Gets a Correlation type with the specified name. + * + * @param correlationtypeName Correlation type name + * @return Correlation type matching the given name, null if none matches. + * + * @throws CentralRepoException + */ + public CorrelationAttributeInstance.Type getCorrelationTypeByName(String correlationtypeName) throws CentralRepoException { + List correlationTypesList = getCorrelationTypes(); + + CorrelationAttributeInstance.Type correlationType + = correlationTypesList.stream() + .filter(x -> correlationtypeName.equalsIgnoreCase(x.getDisplayName())) + .findAny() + .orElse(null); + + return null; + } + + /** * Get the EamArtifact.Type that has the given Type.Id from the central repo * @@ -3142,6 +3185,30 @@ abstract class RdbmsCentralRepo implements CentralRepository { } } + /** + * Reads the correlation types from the database and loads them up in the cache. + * + * @throws CentralRepoException If there is an error. + */ + private void getCorrelationTypesFromCr() throws CentralRepoException { + + // clear out the cache + typeCache.invalidateAll(); + + String sql = "SELECT * FROM correlation_types"; + try ( Connection conn = connect(); + PreparedStatement preparedStatement = conn.prepareStatement(sql); + ResultSet resultSet = preparedStatement.executeQuery();) { + + while (resultSet.next()) { + CorrelationAttributeInstance.Type aType = getCorrelationTypeFromResultSet(resultSet); + typeCache.put(aType.getId(), aType); + } + } catch (SQLException ex) { + throw new CentralRepoException("Error getting correlation types.", ex); // NON-NLS + } + } + /** * Convert a ResultSet to a EamCase object * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java index 33b6009dea..963809c5d7 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepoFactory.java @@ -19,12 +19,17 @@ package org.sleuthkit.autopsy.centralrepository.datamodel; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona.Confidence; +import org.sleuthkit.autopsy.centralrepository.datamodel.Persona.PersonaStatus; import static org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepo.SOFTWARE_CR_DB_SCHEMA_VERSION; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.Account; /** * Creates the CR schema and populates it with initial data. @@ -76,7 +81,7 @@ public class RdbmsCentralRepoFactory { * connectionPool object directly. */ public boolean initializeDatabaseSchema() { - + String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate(selectedPlatform); String instancesCaseIdIdx = getAddCaseIdIndexTemplate(); @@ -87,89 +92,88 @@ public class RdbmsCentralRepoFactory { // NOTE: the db_info table currenly only has 1 row, so having an index // provides no benefit. - Connection conn = null; - Statement stmt = null; - try { - conn = this.getEphemeralConnection(); + try (Connection conn = this.getEphemeralConnection();) { + if (null == conn) { LOGGER.log(Level.SEVERE, "Cannot initialize CR database, don't have a valid connection."); // NON-NLS return false; } - - stmt = conn.createStatement(); - // these setting PRAGMAs are SQLIte spcific - if (selectedPlatform == CentralRepoPlatforms.SQLITE) { - stmt.execute(PRAGMA_JOURNAL_WAL); - stmt.execute(PRAGMA_SYNC_OFF); - stmt.execute(PRAGMA_READ_UNCOMMITTED_TRUE); - stmt.execute(PRAGMA_ENCODING_UTF8); - stmt.execute(PRAGMA_PAGE_SIZE_4096); - stmt.execute(PRAGMA_FOREIGN_KEYS_ON); - } + try (Statement stmt = conn.createStatement();) { - // Create Organizations table - stmt.execute(getCreateOrganizationsTableStatement(selectedPlatform)); - - // Create Cases table and indexes - stmt.execute(getCreateCasesTableStatement(selectedPlatform)); - stmt.execute(getCasesOrgIdIndexStatement()); - stmt.execute(getCasesCaseUidIndexStatement()); - - stmt.execute(getCreateDataSourcesTableStatement(selectedPlatform)); - stmt.execute(getAddDataSourcesNameIndexStatement()); - stmt.execute(getAddDataSourcesObjectIdIndexStatement()); - - stmt.execute(getCreateReferenceSetsTableStatement(selectedPlatform)); - stmt.execute(getReferenceSetsOrgIdIndexTemplate()); - - stmt.execute(getCreateCorrelationTypesTableStatement(selectedPlatform)); - - stmt.execute(getCreateDbInfoTableStatement(selectedPlatform)); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); - stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); - - // Create a separate instance and reference table for each artifact type - List DEFAULT_CORRELATION_TYPES = CorrelationAttributeInstance.getDefaultCorrelationTypes(); - - String reference_type_dbname; - String instance_type_dbname; - for (CorrelationAttributeInstance.Type type : DEFAULT_CORRELATION_TYPES) { - reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); - instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); - - stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname)); - stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname)); - - // FUTURE: allow more than the FILES type - if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { - stmt.execute(String.format(getReferenceTypesTableTemplate(selectedPlatform), reference_type_dbname, reference_type_dbname)); - stmt.execute(String.format(getReferenceTypeValueIndexTemplate(), reference_type_dbname, reference_type_dbname)); - stmt.execute(String.format(getReferenceTypeValueKnownstatusIndexTemplate(), reference_type_dbname, reference_type_dbname)); + // these setting PRAGMAs are SQLIte spcific + if (selectedPlatform == CentralRepoPlatforms.SQLITE) { + stmt.execute(PRAGMA_JOURNAL_WAL); + stmt.execute(PRAGMA_SYNC_OFF); + stmt.execute(PRAGMA_READ_UNCOMMITTED_TRUE); + stmt.execute(PRAGMA_ENCODING_UTF8); + stmt.execute(PRAGMA_PAGE_SIZE_4096); + stmt.execute(PRAGMA_FOREIGN_KEYS_ON); } + + // Create Organizations table + stmt.execute(getCreateOrganizationsTableStatement(selectedPlatform)); + + // Create Cases table and indexes + stmt.execute(getCreateCasesTableStatement(selectedPlatform)); + stmt.execute(getCasesOrgIdIndexStatement()); + stmt.execute(getCasesCaseUidIndexStatement()); + + stmt.execute(getCreateDataSourcesTableStatement(selectedPlatform)); + stmt.execute(getAddDataSourcesNameIndexStatement()); + stmt.execute(getAddDataSourcesObjectIdIndexStatement()); + + stmt.execute(getCreateReferenceSetsTableStatement(selectedPlatform)); + stmt.execute(getReferenceSetsOrgIdIndexTemplate()); + + stmt.execute(getCreateCorrelationTypesTableStatement(selectedPlatform)); + + stmt.execute(getCreateDbInfoTableStatement(selectedPlatform)); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')"); + stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')"); + + // Create account_types and accounts tab;es which are referred by X_instances tables + stmt.execute(getCreateAccountTypesTableStatement(selectedPlatform)); + stmt.execute(getCreateAccountsTableStatement(selectedPlatform)); + + // Create a separate instance and reference table for each artifact type + List defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + + String reference_type_dbname; + String instance_type_dbname; + for (CorrelationAttributeInstance.Type type : defaultCorrelationTypes) { + reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type); + instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type); + + stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname)); + stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname)); + + // FUTURE: allow more than the FILES type + if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) { + stmt.execute(String.format(getReferenceTypesTableTemplate(selectedPlatform), reference_type_dbname, reference_type_dbname)); + stmt.execute(String.format(getReferenceTypeValueIndexTemplate(), reference_type_dbname, reference_type_dbname)); + stmt.execute(String.format(getReferenceTypeValueKnownstatusIndexTemplate(), reference_type_dbname, reference_type_dbname)); + } + } + createPersonaTables(stmt); + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS + return false; + } catch (CentralRepoException ex) { + LOGGER.log(Level.SEVERE, "Error getting default correlation types. Likely due to one or more Type's with an invalid db table name."); // NON-NLS + return false; } } catch (SQLException ex) { - LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS + LOGGER.log(Level.SEVERE, "Error connecting to database.", ex); // NON-NLS return false; - } catch (CentralRepoException ex) { - LOGGER.log(Level.SEVERE, "Error getting default correlation types. Likely due to one or more Type's with an invalid db table name."); // NON-NLS - return false; - } finally { - if (stmt != null) { - try { - stmt.close(); - } catch (SQLException ex2) { - LOGGER.log(Level.SEVERE, "Error closing statement.", ex2); - } - } - CentralRepoDbUtil.closeConnection(conn); } + return true; } @@ -179,13 +183,22 @@ public class RdbmsCentralRepoFactory { * @return True if success, False otherwise. */ public boolean insertDefaultDatabaseContent() { - Connection conn = this.getEphemeralConnection(); - if (null == conn) { + + boolean result; + try (Connection conn = this.getEphemeralConnection();) { + if (null == conn) { + return false; + } + + result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) + && CentralRepoDbUtil.insertDefaultOrganization(conn) + && insertDefaultPersonaTablesContent(conn); + + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in CR tables."), ex); return false; } - boolean result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn) && CentralRepoDbUtil.insertDefaultOrganization(conn); - CentralRepoDbUtil.closeConnection(conn); return result; } @@ -353,12 +366,14 @@ public class RdbmsCentralRepoFactory { + getNumericPrimaryKeyClause("id", selectedPlatform) + "case_id integer NOT NULL," + "data_source_id integer NOT NULL," + + "account_id " + getBigIntType(selectedPlatform) + " DEFAULT NULL," + "value text NOT NULL," + "file_path text NOT NULL," + "known_status integer NOT NULL," + "comment text," + "file_obj_id " + getBigIntType(selectedPlatform) + " ," + "CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path)" + getOnConflictIgnoreClause(selectedPlatform) + "," + + "foreign key (account_id) references accounts(id)," + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," + "foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL)"; } @@ -413,7 +428,7 @@ public class RdbmsCentralRepoFactory { /** * Get the template for creating an index on the value column of an instance * table. %s will exist in the template where the name of the new table will - * be addedd. + * be added. * * @return a String which is a template for adding an index to the value * column of a _instances table @@ -426,7 +441,7 @@ public class RdbmsCentralRepoFactory { /** * Get the template for creating an index on the known_status column of an * instance table. %s will exist in the template where the name of the new - * table will be addedd. + * table will be added. * * @return a String which is a template for adding an index to the * known_status column of a _instances table @@ -439,7 +454,7 @@ public class RdbmsCentralRepoFactory { /** * Get the template for creating an index on the file_obj_id column of an * instance table. %s will exist in the template where the name of the new - * table will be addedd. + * table will be added. * * @return a String which is a template for adding an index to the * file_obj_id column of a _instances table @@ -525,7 +540,16 @@ public class RdbmsCentralRepoFactory { } } - + private static String getOnConflictDoNothingClause(CentralRepoPlatforms selectedPlatform) { + switch (selectedPlatform) { + case POSTGRESQL: + return "ON CONFLICT DO NOTHING"; + case SQLITE: + return ""; + default: + return ""; + } + } /** * Returns an ephemeral connection to the CR database. * @@ -541,4 +565,301 @@ public class RdbmsCentralRepoFactory { return null; } } + + /** + * Creates the tables for Persona. + * + * @return True if success, False otherwise. + */ + private boolean createPersonaTables(Statement stmt) throws SQLException { + + stmt.execute(getCreateConfidenceTableStatement(selectedPlatform)); + stmt.execute(getCreateExaminersTableStatement(selectedPlatform)); + stmt.execute(getCreatePersonaStatusTableStatement(selectedPlatform)); + stmt.execute(getCreateAliasesTableStatement(selectedPlatform)); + + stmt.execute(getCreatePersonasTableStatement(selectedPlatform)); + stmt.execute(getCreatePersonaAliasTableStatement(selectedPlatform)); + stmt.execute(getCreatePersonaMetadataTableStatement(selectedPlatform)); + stmt.execute(getCreatePersonaAccountsTableStatement(selectedPlatform)); + + return true; + } + + + /** + * Get the SQL string for creating a new account_types table in a central + * repository. + * + * @return SQL string for creating account_types table + */ + static String getCreateAccountTypesTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS account_types (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "type_name TEXT NOT NULL," + + "display_name TEXT NOT NULL," + + "correlation_type_id " + getBigIntType(selectedPlatform) + " ," + + "CONSTRAINT type_name_unique UNIQUE (type_name)," + + "FOREIGN KEY (correlation_type_id) REFERENCES correlation_types(id)" + + ")"; + } + + /** + * Get the SQL String for creating a new confidence table in a central + * repository. + * + * @return SQL string for creating confidence table + */ + static String getCreateConfidenceTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS confidence (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "confidence_id integer NOT NULL," + + "description TEXT," + + "CONSTRAINT level_unique UNIQUE (confidence_id)" + + ")"; + } + + /** + * Get the SQL String for creating a new examiners table in a central + * repository. + * + * @return SQL string for creating examiners table + */ + static String getCreateExaminersTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS examiners (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "login_name TEXT NOT NULL," + + "display_name TEXT," + + "CONSTRAINT login_name_unique UNIQUE(login_name)" + + ")"; + } + + /** + * Get the SQL String for creating a new persona_status table in a central + * repository. + * + * @return SQL string for creating persona_status table + */ + static String getCreatePersonaStatusTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS persona_status (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "status_id integer NOT NULL," + + "status TEXT NOT NULL," + + "CONSTRAINT status_unique UNIQUE(status_id)" + + ")"; + } + + /** + * Get the SQL String for creating a new aliases table in a central + * repository. + * + * @return SQL string for creating aliases table + */ + static String getCreateAliasesTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS aliases (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "alias TEXT NOT NULL," + + "CONSTRAINT alias_unique UNIQUE(alias)" + + ")"; + } + + /** + * Get the SQL String for creating a new accounts table in a central + * repository. + * + * @return SQL string for creating accounts table + */ + static String getCreateAccountsTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS accounts (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "account_type_id integer NOT NULL," + + "account_unique_identifier TEXT NOT NULL," + + "CONSTRAINT account_unique UNIQUE(account_type_id, account_unique_identifier)," + + "FOREIGN KEY (account_type_id) REFERENCES account_types(id)" + + ")"; + } + + /** + * Get the SQL String for creating a new personas table in a central + * repository. + * + * @return SQL string for creating personas table + */ + static String getCreatePersonasTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS personas (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "uuid TEXT NOT NULL," + + "comment TEXT NOT NULL," + + "name TEXT NOT NULL," + + "created_date " + getBigIntType(selectedPlatform) + " ," + + "modified_date " + getBigIntType(selectedPlatform) + " ," + + "status_id integer NOT NULL," + + "CONSTRAINT uuid_unique UNIQUE(uuid)," + + "FOREIGN KEY (status_id) REFERENCES persona_status(status_id)" + + ")"; + } + + /** + * Get the SQL String for creating a new persona_alias table in a central + * repository. + * + * @return SQL string for creating persona_alias table + */ + static String getCreatePersonaAliasTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS persona_alias (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "persona_id " + getBigIntType(selectedPlatform) + " ," + + "alias_id " + getBigIntType(selectedPlatform) + " ," + + "justification TEXT NOT NULL," + + "confidence_id integer NOT NULL," + + "date_added " + getBigIntType(selectedPlatform) + " ," + + "examiner_id integer NOT NULL," + + "FOREIGN KEY (persona_id) REFERENCES personas(id)," + + "FOREIGN KEY (alias_id) REFERENCES aliases(id)," + + "FOREIGN KEY (confidence_id) REFERENCES confidence(confidence_id)," + + "FOREIGN KEY (examiner_id) REFERENCES examiners(id)" + + ")"; + } + + /** + * Get the SQL String for creating a new persona_metadata table in a central + * repository. + * + * @return SQL string for creating persona_metadata table + */ + static String getCreatePersonaMetadataTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS persona_metadata (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "persona_id " + getBigIntType(selectedPlatform) + " ," + + "name TEXT NOT NULL," + + "value TEXT NOT NULL," + + "justification TEXT NOT NULL," + + "confidence_id integer NOT NULL," + + "date_added " + getBigIntType(selectedPlatform) + " ," + + "examiner_id integer NOT NULL," + + "CONSTRAINT unique_metadata UNIQUE(persona_id, name)," + + "FOREIGN KEY (persona_id) REFERENCES personas(id)," + + "FOREIGN KEY (confidence_id) REFERENCES confidence(confidence_id)," + + "FOREIGN KEY (examiner_id) REFERENCES examiners(id)" + + ")"; + } + + /** + * Get the SQL String for creating a new persona_accounts table in a central + * repository. + * + * @return SQL string for creating persona_accounts table + */ + static String getCreatePersonaAccountsTableStatement(CentralRepoPlatforms selectedPlatform) { + + return "CREATE TABLE IF NOT EXISTS persona_accounts (" + + getNumericPrimaryKeyClause("id", selectedPlatform) + + "persona_id " + getBigIntType(selectedPlatform) + " ," + + "account_id " + getBigIntType(selectedPlatform) + " ," + + "justification TEXT NOT NULL," + + "confidence_id integer NOT NULL," + + "date_added " + getBigIntType(selectedPlatform) + " ," + + "examiner_id integer NOT NULL," + + "FOREIGN KEY (persona_id) REFERENCES personas(id)," + + "FOREIGN KEY (account_id) REFERENCES accounts(id)," + + "FOREIGN KEY (confidence_id) REFERENCES confidence(confidence_id)," + + "FOREIGN KEY (examiner_id) REFERENCES examiners(id)" + + ")"; + } + + + /** + * Inserts the default content in persona related tables. + * + * @param conn Database connection to use. + * + * @return True if success, false otherwise. + */ + private boolean insertDefaultPersonaTablesContent(Connection conn) { + + Statement stmt = null; + try { + stmt = conn.createStatement(); + + // populate the confidence table + for (Confidence confidence : Persona.Confidence.values()) { + String sqlString = "INSERT INTO confidence (confidence_id, description) VALUES ( " + confidence.getLevel() + ", '" + confidence.toString() + "')" //NON-NLS + + getOnConflictDoNothingClause(selectedPlatform); + stmt.execute(sqlString); + } + + // populate the persona_status table + for (PersonaStatus status : Persona.PersonaStatus.values()) { + String sqlString = "INSERT INTO persona_status (status_id, status) VALUES ( " + status.getStatus() + ", '" + status.toString() + "')" //NON-NLS + + getOnConflictDoNothingClause(selectedPlatform); + stmt.execute(sqlString); + } + + // Populate the account_types table + for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) { + int correlationTypeId = getCorrelationTypeIdForAccountType(conn, type); + if (correlationTypeId > 0) { + String sqlString = String.format("INSERT INTO account_types (type_name, display_name, correlation_type_id) VALUES ('%s', '%s', %d)" + getOnConflictDoNothingClause(selectedPlatform), + type.getTypeName(), type.getDisplayName(), correlationTypeId); + stmt.execute(sqlString); + } + } + + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in Persona tables."), ex); + return false; + } finally { + if (stmt != null) { + try { + stmt.close(); + } catch (SQLException ex2) { + LOGGER.log(Level.SEVERE, "Error closing statement.", ex2); + } + } + } + + return true; + } + + /** + * Returns the correlation type id for the given account type, + * from the correlation_types table. + * + * @param conn Connection to use for database query. + * @param accountType Account type to look for. + * ' + * @return correlation type id. + */ + private int getCorrelationTypeIdForAccountType(Connection conn, Account.Type accountType) { + + int typeId = -1; + if (accountType == Account.Type.EMAIL) { + typeId = CorrelationAttributeInstance.EMAIL_TYPE_ID; + } else if (accountType == Account.Type.PHONE) { + typeId = CorrelationAttributeInstance.PHONE_TYPE_ID; + } else { + String querySql = "SELECT * FROM correlation_types WHERE display_name=?"; + try ( PreparedStatement preparedStatementQuery = conn.prepareStatement(querySql)) { + preparedStatementQuery.setString(1, accountType.getDisplayName()); + try (ResultSet resultSet = preparedStatementQuery.executeQuery();) { + if (resultSet.next()) { + typeId = resultSet.getInt("id"); + } + } + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to get correlation typeId for account type %s.", accountType.getTypeName()), ex); + } + } + + return typeId; + } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Bundle.properties-MERGED index b7c3df2c53..cd654a5b37 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Bundle.properties-MERGED @@ -7,3 +7,6 @@ IngestEventsListener.prevCount.text=Number of previous {0}: {1} IngestEventsListener.prevExists.text=Previously Seen Devices (Central Repository) IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository) Installer.centralRepoUpgradeFailed.title=Central repository disabled +Installer.initialCreateSqlite.messageDesc=It will store information about all hashes and identifiers that you process. You can use this to ignore previously seen files and make connections between cases. +Installer.initialCreateSqlite.messageHeader=The Central Repository is not enabled. Would you like to? +Installer.initialCreateSqlite.title=Enable Central Repository? 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/commonpropertiessearch/CommonAttributeCaseSearchResults.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCaseSearchResults.java index 0f87533504..e096638434 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCaseSearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCaseSearchResults.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -123,8 +123,7 @@ final public class CommonAttributeCaseSearchResults { if (currentCaseDataSourceMap == null) { //there are no results return filteredCaseNameToDataSourcesTree; } - CorrelationAttributeInstance.Type attributeType = CorrelationAttributeInstance - .getDefaultCorrelationTypes() + CorrelationAttributeInstance.Type attributeType = CentralRepository.getInstance().getCorrelationTypes() .stream() .filter(filterType -> filterType.getId() == resultTypeId) .findFirst().get(); diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCountSearchResults.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCountSearchResults.java index 18e7195f34..85923e53b6 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCountSearchResults.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributeCountSearchResults.java @@ -128,14 +128,13 @@ final public class CommonAttributeCountSearchResults { return; } - CorrelationAttributeInstance.Type attributeType = CorrelationAttributeInstance - .getDefaultCorrelationTypes() + CentralRepository eamDb = CentralRepository.getInstance(); + CorrelationAttributeInstance.Type attributeType = eamDb.getCorrelationTypes() .stream() .filter(filterType -> filterType.getId() == this.resultTypeId) .findFirst().get(); - CentralRepository eamDb = CentralRepository.getInstance(); - + Map> itemsToRemove = new HashMap<>(); //Call countUniqueDataSources once to reduce the number of DB queries needed to get //the frequencyPercentage diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributePanel.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributePanel.java index f56f9dd9a8..43d834e39d 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributePanel.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/CommonAttributePanel.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"); @@ -255,7 +255,7 @@ final class CommonAttributePanel extends javax.swing.JDialog implements Observer filterByDocuments = interCasePanel.documentsCheckboxIsSelected(); } if (corType == null) { - corType = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(0); + corType = CentralRepository.getInstance().getCorrelationTypes().get(0); } if (caseId == InterCasePanel.NO_CASE_SELECTED) { builder = new AllInterCaseCommonAttributeSearcher(filterByMedia, filterByDocuments, corType, percentageThreshold); @@ -366,7 +366,7 @@ final class CommonAttributePanel extends javax.swing.JDialog implements Observer filterByDocuments = interCasePanel.documentsCheckboxIsSelected(); } if (corType == null) { - corType = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(0); + corType = CentralRepository.getInstance().getCorrelationTypes().get(0); } if (caseId == InterCasePanel.NO_CASE_SELECTED) { builder = new AllInterCaseCommonAttributeSearcher(filterByMedia, filterByDocuments, corType, percentageThreshold); diff --git a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java index 88d60db3be..a2c1c01529 100644 --- a/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java +++ b/Core/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCasePanel.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,6 +31,7 @@ import java.util.logging.Level; import javax.swing.ComboBoxModel; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -117,7 +118,7 @@ public final class InterCasePanel extends javax.swing.JPanel { void setupCorrelationTypeFilter() { this.correlationTypeFilters = new HashMap<>(); try { - List types = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + List types = CentralRepository.getInstance().getCorrelationTypes(); for (CorrelationAttributeInstance.Type type : types) { correlationTypeFilters.put(type.getDisplayName(), type); this.correlationTypeComboBox.addItem(type.getDisplayName()); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java index 5105f1628d..49617c9dfb 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/CorrelationCaseChildNodeFactory.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -111,7 +111,7 @@ final class CorrelationCaseChildNodeFactory extends ChildFactory(); - List correcationTypeList = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + List correcationTypeList = CentralRepository.getInstance().getCorrelationTypes(); correcationTypeList.forEach((type) -> { correlationTypeMap.put(type.getId(), type); }); 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/core/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED index c84f1f1b86..0b16a9701f 100755 --- a/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/core/Bundle.properties-MERGED @@ -3,7 +3,13 @@ Installer.closing.confirmationDialog.title=Ingest is Running # {0} - exception message Installer.closing.messageBox.caseCloseExceptionMessage=Error closing case: {0} OpenIDE-Module-Display-Category=Infrastructure -OpenIDE-Module-Long-Description=This is the core Autopsy module.\n\nThe module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\nThe framework included in the module contains APIs for developing modules for ingest, viewers and reporting. The modules can be deployed as Plugins using the Autopsy plugin installer.\nThis module should not be uninstalled - without it, Autopsy will not run.\n\nFor more information, see http://www.sleuthkit.org/autopsy/ +OpenIDE-Module-Long-Description=\ + This is the core Autopsy module.\n\n\ + The module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\n\ + The framework included in the module contains APIs for developing modules for ingest, viewers and reporting. \ + The modules can be deployed as Plugins using the Autopsy plugin installer.\n\ + This module should not be uninstalled - without it, Autopsy will not run.\n\n\ + For more information, see http://www.sleuthkit.org/autopsy/ OpenIDE-Module-Name=Autopsy-Core OpenIDE-Module-Short-Description=Autopsy Core Module org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xml diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED index f252420726..9f363b7723 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties-MERGED @@ -63,9 +63,9 @@ DataContentViewerHex.totalPageLabel.text_1=100 DataContentViewerHex.pageLabel2.text=Page # Product Information panel -LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
+LBL_Description=
\n Product Version: {0} ({9})
Sleuth Kit Version: {7}
Netbeans RCP Build: {8}
Java: {1}; {2}
System: {3}; {4}; {5}
Userdir: {6}
Format_OperatingSystem_Value={0} version {1} running on {2} -LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2018.
+LBL_Copyright=
Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools.
Copyright © 2003-2018.
SortChooser.dialogTitle=Choose Sort Criteria ThumbnailViewChildren.progress.cancelling=(Cancelling) # {0} - file name @@ -95,7 +95,7 @@ DataResultViewerThumbnail.pageNextButton.text= DataResultViewerThumbnail.imagesLabel.text=Images: DataResultViewerThumbnail.imagesRangeLabel.text=- DataResultViewerThumbnail.pageNumLabel.text=- -DataResultViewerThumbnail.filePathLabel.text=\ +DataResultViewerThumbnail.filePathLabel.text=\ \ \ DataResultViewerThumbnail.goToPageLabel.text=Go to Page: DataResultViewerThumbnail.goToPageField.text= AdvancedConfigurationDialog.cancelButton.text=Cancel diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED index 18e279dd2c..a0d535f8e6 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Bundle.properties-MERGED @@ -30,7 +30,9 @@ PlatformUtil.getProcVmUsed.sigarNotInit.msg=Cannot get virt mem used, sigar not PlatformUtil.getProcVmUsed.gen.msg=Cannot get virt mem used, {0} PlatformUtil.getJvmMemInfo.usageText=JVM heap usage: {0}, JVM non-heap usage: {1} PlatformUtil.getPhysicalMemInfo.usageText=Physical memory usage (max, total, free): {0}, {1}, {2} -PlatformUtil.getAllMemUsageInfo.usageText={0}\n{1}\nProcess Virtual Memory: {2} +PlatformUtil.getAllMemUsageInfo.usageText={0}\n\ +{1}\n\ +Process Virtual Memory: {2} # {0} - file name ReadImageTask.mesageText=Reading image: {0} StringExtract.illegalStateException.cannotInit.msg=Unicode table not properly initialized, cannot instantiate StringExtract 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(); diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties index 6a4b6e4047..108b3608fa 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties @@ -65,8 +65,6 @@ FileSearchPanel.stepTwoLabel.text=Step 2: Filter which images to show FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings DiscoveryTopComponent.stepOneLabel.text=Step 1: Pick File Type DiscoveryTopComponent.documentsButton.text=Documents -DocumentPanel.countLabel.toolTipText= DocumentPanel.fileSizeLabel.toolTipText= -DocumentPanel.documentType.text= DocumentPanel.isDeletedLabel.toolTipText= ImageThumbnailPanel.isDeletedLabel.toolTipText= diff --git a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED index d438e929eb..ea9e846568 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filequery/Bundle.properties-MERGED @@ -14,8 +14,8 @@ DiscoveryUiUtility.megaBytes.text=MB # {1} - units DiscoveryUiUtility.sizeLabel.text=Size: {0} {1} DiscoveryUiUtility.terraBytes.text=TB -# {0} - extension -DocumentPanel.documentType.extension.text=Extension: {0} +# {0} - otherInstanceCount +DocumentPanel.nameLabel.more.text=\ and {0} more DocumentWrapper.previewInitialValue=Preview not generated yet. FileGroup.groupSortingAlgorithm.groupName.text=Group Name FileGroup.groupSortingAlgorithm.groupSize.text=Group Size @@ -24,6 +24,8 @@ FileGroup.groupSortingAlgorithm.groupSize.text=Group Size FileSearch.DataSourceGroupKey.datasourceAndID={0}(ID: {1}) # {0} - Data source ID FileSearch.DataSourceGroupKey.idOnly=Data source (ID: {0}) +FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview. +FileSearch.documentSummary.noPreview=No preview available. FileSearch.FileTagGroupKey.noSets=None # {0} - file name FileSearch.genVideoThumb.progress.text=extracting temporary file {0} @@ -173,9 +175,9 @@ FileSorter.SortingMethod.fullPath.displayName=Full Path FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names GroupsListPanel.noResults.message.text=No results were found for the selected filters. GroupsListPanel.noResults.title.text=No results found -# {0} - numberOfInstances -ImageThumbnailPanel.countLabel.text=Number of Instances: {0} ImageThumbnailPanel.isDeleted.text=All instances of file are deleted. +# {0} - otherInstanceCount +ImageThumbnailPanel.nameLabel.more.text=\ and {0} more OpenFileDiscoveryAction.resultsIncomplete.text=Results may be incomplete ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it. ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable. @@ -185,8 +187,7 @@ ResultFile.score.taggedFile.description=At least one instance of the file has be # {1} - totalPages ResultsPanel.currentPage.displayValue=Page: {0} of {1} ResultsPanel.currentPageLabel.text=Page: - -ResultsPanel.documentPreviewWorker.noBytes=No bytes read for document, unable to display preview. -ResultsPanel.documentPreviewWorker.noPreview=No preview available. +ResultsPanel.documentPreview.text=Document preview creation cancelled. # {0} - selectedPage # {1} - maxPage ResultsPanel.invalidPageNumber.message=The selected page number {0} does not exist. Please select a value from 1 to {1}. @@ -209,19 +210,18 @@ FileSearchPanel.stepTwoLabel.text=Step 2: Filter which images to show FileSearchPanel.stepThreeLabel.text=Step 3: Choose display settings DiscoveryTopComponent.stepOneLabel.text=Step 1: Pick File Type DiscoveryTopComponent.documentsButton.text=Documents -DocumentPanel.countLabel.toolTipText= DocumentPanel.fileSizeLabel.toolTipText= -DocumentPanel.documentType.text= DocumentPanel.isDeletedLabel.toolTipText= ImageThumbnailPanel.isDeletedLabel.toolTipText= +ResultsPanel.unableToCreate.text=Unable to create summary. ResultsPanel.viewFileInDir.name=View File in Directory VideoThumbnailPanel.bytes.text=bytes -# {0} - numberOfInstances -VideoThumbnailPanel.countLabel.text=Number of Instances: {0} VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB VideoThumbnailPanel.kiloBytes.text=KB VideoThumbnailPanel.megaBytes.text=MB +# {0} - otherInstanceCount +VideoThumbnailPanel.nameLabel.more.text=\ and {0} more # {0} - fileSize # {1} - units VideoThumbnailPanel.sizeLabel.text=Size: {0} {1} diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form index 8608d528b3..05ed6fc0c8 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.form @@ -27,15 +27,14 @@ - - + + - - - + + @@ -45,16 +44,14 @@ - + - - - + @@ -62,22 +59,6 @@ - - - - - - - - - - - - - - - - @@ -121,12 +102,7 @@ - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java index 8fea944747..849d3843ec 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/DocumentPanel.java @@ -52,21 +52,15 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere // //GEN-BEGIN:initComponents private void initComponents() { - countLabel = new javax.swing.JLabel(); isDeletedLabel = new javax.swing.JLabel(); scoreLabel = new javax.swing.JLabel(); fileSizeLabel = new javax.swing.JLabel(); - documentType = new javax.swing.JLabel(); + nameLabel = new javax.swing.JLabel(); javax.swing.JScrollPane previewScrollPane = new javax.swing.JScrollPane(); previewTextArea = new javax.swing.JTextArea(); setBorder(javax.swing.BorderFactory.createEtchedBorder()); - countLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.countLabel.toolTipText")); // NOI18N - countLabel.setMaximumSize(new java.awt.Dimension(159, 12)); - countLabel.setMinimumSize(new java.awt.Dimension(159, 12)); - countLabel.setPreferredSize(new java.awt.Dimension(159, 12)); - isDeletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N isDeletedLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.isDeletedLabel.toolTipText")); // NOI18N isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); @@ -81,8 +75,6 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere fileSizeLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.fileSizeLabel.toolTipText")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(documentType, org.openide.util.NbBundle.getMessage(DocumentPanel.class, "DocumentPanel.documentType.text")); // NOI18N - previewScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); previewTextArea.setEditable(false); @@ -104,57 +96,55 @@ public class DocumentPanel extends javax.swing.JPanel implements ListCellRendere .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(countLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 530, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 81, Short.MAX_VALUE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(previewScrollPane) - .addComponent(documentType, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(previewScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 649, Short.MAX_VALUE) + .addComponent(nameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() - .addComponent(documentType, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(nameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(previewScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(countLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel countLabel; - private javax.swing.JLabel documentType; private javax.swing.JLabel fileSizeLabel; private javax.swing.JLabel isDeletedLabel; + private javax.swing.JLabel nameLabel; private javax.swing.JTextArea previewTextArea; private javax.swing.JLabel scoreLabel; // End of variables declaration//GEN-END:variables - @Messages({"# {0} - extension", - "DocumentPanel.documentType.extension.text=Extension: {0}"}) + @Messages({"# {0} - otherInstanceCount", + "DocumentPanel.nameLabel.more.text= and {0} more"}) @Override public Component getListCellRendererComponent(JList list, DocumentWrapper value, int index, boolean isSelected, boolean cellHasFocus) { fileSizeLabel.setText(DiscoveryUiUtils.getFileSizeString(value.getResultFile().getFirstInstance().getSize())); - countLabel.setText(Bundle.ImageThumbnailPanel_countLabel_text(value.getResultFile().getAllInstances().size())); - documentType.setText(Bundle.DocumentPanel_documentType_extension_text(value.getResultFile().getFirstInstance().getNameExtension())); //WJS-TODO fill this in with a document type instead of just DOCUMENT + String nameText = value.getResultFile().getFirstInstance().getParentPath() + value.getResultFile().getFirstInstance().getName(); + if (value.getResultFile().getAllInstances().size() > 1) { + nameText += Bundle.DocumentPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1); + } + nameLabel.setText(nameText); previewTextArea.setText(value.getPreview()); previewTextArea.setCaretPosition(0); DiscoveryUiUtils.setDeletedIcon(value.getResultFile().isDeleted(), isDeletedLabel); DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); - return this; } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java index 8e55eb50e6..ee5c36c8e3 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/FileSearch.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,11 +25,13 @@ import java.awt.Image; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.IOException; +import java.io.Reader; import java.nio.file.Paths; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -43,9 +45,11 @@ import java.util.logging.Level; import javax.imageio.ImageIO; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.StringUtils; import org.netbeans.api.progress.ProgressHandle; import org.opencv.core.Mat; import org.opencv.highgui.VideoCapture; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -71,6 +75,9 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.textextractors.TextExtractor; +import org.sleuthkit.autopsy.textextractors.TextExtractorFactory; +import org.sleuthkit.autopsy.textsummarizer.TextSummarizer; /** * Main class to perform the file search. @@ -84,6 +91,8 @@ class FileSearch { private static final Cache>> searchCache = CacheBuilder.newBuilder() .maximumSize(MAXIMUM_CACHE_SIZE) .build(); + private static final int PREVIEW_SIZE = 256; + private static volatile TextSummarizer summarizerToUse = null; /** * Run the file search and returns the SearchResults object for debugging. @@ -239,6 +248,78 @@ class FileSearch { return page; } + /** + * Get a summary for the specified AbstractFile. If no TextSummarizers exist + * get the beginning of the file. + * + * @param file The AbstractFile to summarize. + * + * @return The summary or beginning of the specified file as a String. + */ + @NbBundle.Messages({"FileSearch.documentSummary.noPreview=No preview available.", + "FileSearch.documentSummary.noBytes=No bytes read for document, unable to display preview."}) + static String summarize(AbstractFile file) { + String summary = null; + TextSummarizer localSummarizer = summarizerToUse; + if (localSummarizer == null) { + synchronized (searchCache) { + if (localSummarizer == null) { + localSummarizer = getLocalSummarizer(); + } + } + } + if (localSummarizer != null) { + try { + //a summary of length 40 seems to fit without vertical scroll bars + summary = localSummarizer.summarize(file, 40); + } catch (IOException ex) { + return Bundle.FileSearch_documentSummary_noPreview(); + } + } + if (StringUtils.isBlank(summary)) { + //no summarizer was found or summary was empty just grab the beginning of the file + summary = getFirstLines(file); + } + return summary; + } + + /** + * Get the beginning of text from the specified AbstractFile. + * + * @param file The AbstractFile to get text from. + * + * @return The beginning of text from the specified AbstractFile. + */ + private static String getFirstLines(AbstractFile file) { + try (Reader reader = TextExtractorFactory.getExtractor(file, null).getReader()) { + char[] cbuf = new char[PREVIEW_SIZE]; + reader.read(cbuf, 0, PREVIEW_SIZE); + return new String(cbuf); + } catch (IOException ex) { + return Bundle.FileSearch_documentSummary_noBytes(); + } catch (TextExtractorFactory.NoTextExtractorFound | TextExtractor.InitReaderException ex) { + return Bundle.FileSearch_documentSummary_noPreview(); + } + } + + /** + * Get the first TextSummarizer found by a lookup of TextSummarizers. + * + * @return The first TextSummarizer found by a lookup of TextSummarizers. + * + * @throws IOException + */ + private static TextSummarizer getLocalSummarizer() { + Collection summarizers + = Lookup.getDefault().lookupAll(TextSummarizer.class + ); + if (!summarizers.isEmpty()) { + summarizerToUse = summarizers.iterator().next(); + return summarizerToUse; + } + return null; + } + /** * Run the file search. Caching new results for access at later time. * @@ -597,7 +678,6 @@ class FileSearch { int framePos = Integer.valueOf(FilenameUtils.getBaseName(fileName).substring(2)); framePositions[thumbnailNumber] = framePos; thumbnailNumber++; - } thumbnailWrapper.setThumbnails(videoThumbnails, framePositions); } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form index ff120eecdd..b491a2c6de 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.form @@ -20,36 +20,36 @@ - + - - - - - + + + + + - + + + - - - + @@ -82,7 +82,7 @@ - + @@ -133,4 +133,4 @@ - \ No newline at end of file + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java index f0c0022905..78654296cb 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ImageThumbnailPanel.java @@ -36,6 +36,7 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR private static final long serialVersionUID = 1L; private static final Color SELECTION_COLOR = new Color(0, 120, 215); + private static final int MAX_NAME_STRING = 30; /** * Creates new form ImageThumbnailPanel @@ -56,7 +57,7 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR javax.swing.JPanel thumbnailPanel = new javax.swing.JPanel(); thumbnailLabel = new javax.swing.JLabel(); fileSizeLabel = new javax.swing.JLabel(); - countLabel = new javax.swing.JLabel(); + nameLabel = new javax.swing.JLabel(); isDeletedLabel = new javax.swing.JLabel(); scoreLabel = new javax.swing.JLabel(); @@ -68,22 +69,22 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR fileSizeLabel.setToolTipText(""); - countLabel.setToolTipText(""); - countLabel.setMaximumSize(new java.awt.Dimension(159, 12)); - countLabel.setMinimumSize(new java.awt.Dimension(159, 12)); - countLabel.setPreferredSize(new java.awt.Dimension(159, 12)); + nameLabel.setToolTipText(""); + nameLabel.setMaximumSize(new java.awt.Dimension(159, 12)); + nameLabel.setMinimumSize(new java.awt.Dimension(159, 12)); + nameLabel.setPreferredSize(new java.awt.Dimension(159, 12)); isDeletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N isDeletedLabel.setToolTipText(org.openide.util.NbBundle.getMessage(ImageThumbnailPanel.class, "ImageThumbnailPanel.isDeletedLabel.toolTipText")); // NOI18N - isDeletedLabel.setMaximumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - isDeletedLabel.setMinimumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - isDeletedLabel.setPreferredSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); + isDeletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + isDeletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + isDeletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); scoreLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); // NOI18N scoreLabel.setToolTipText(""); - scoreLabel.setMaximumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - scoreLabel.setMinimumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - scoreLabel.setPreferredSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); + scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -92,53 +93,60 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(thumbnailPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 201, Short.MAX_VALUE) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() - .addComponent(countLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 163, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(nameLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(thumbnailPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 201, Short.MAX_VALUE))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() + .addComponent(nameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(thumbnailPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(isDeletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(countLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel countLabel; private javax.swing.JLabel fileSizeLabel; private javax.swing.JLabel isDeletedLabel; + private javax.swing.JLabel nameLabel; private javax.swing.JLabel scoreLabel; private javax.swing.JLabel thumbnailLabel; // End of variables declaration//GEN-END:variables @NbBundle.Messages({ - "# {0} - numberOfInstances", - "ImageThumbnailPanel.countLabel.text=Number of Instances: {0}", + "# {0} - otherInstanceCount", + "ImageThumbnailPanel.nameLabel.more.text= and {0} more", "ImageThumbnailPanel.isDeleted.text=All instances of file are deleted."}) @Override public Component getListCellRendererComponent(JList list, ImageThumbnailWrapper value, int index, boolean isSelected, boolean cellHasFocus) { fileSizeLabel.setText(DiscoveryUiUtils.getFileSizeString(value.getResultFile().getFirstInstance().getSize())); - countLabel.setText(Bundle.ImageThumbnailPanel_countLabel_text(value.getResultFile().getAllInstances().size())); + String nameText = value.getResultFile().getFirstInstance().getParentPath() + value.getResultFile().getFirstInstance().getName(); + if (value.getResultFile().getAllInstances().size() > 1) { + nameText += Bundle.ImageThumbnailPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1); + } + if (nameText.length() > MAX_NAME_STRING) { + nameText = "..." + nameText.substring(nameText.length() - (MAX_NAME_STRING - 3)); + } + nameLabel.setText(nameText); thumbnailLabel.setIcon(new ImageIcon(value.getThumbnail())); DiscoveryUiUtils.setDeletedIcon(value.getResultFile().isDeleted(), isDeletedLabel); - DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); + DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); return this; @@ -163,5 +171,4 @@ public class ImageThumbnailPanel extends javax.swing.JPanel implements ListCellR return null; } - } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java index 6ac9a79489..4711303123 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/ResultsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,6 +28,8 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; @@ -38,14 +40,12 @@ import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionListener; -import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.StringExtract; import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -702,6 +702,13 @@ public class ResultsPanel extends javax.swing.JPanel { @Override protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Video Worker Exception for file: " + thumbnailWrapper.getResultFile().getFirstInstance().getId(), ex); + } catch (CancellationException ignored) { + //we want to do nothing in response to this since we allow it to be cancelled + } videoThumbnailViewer.repaint(); } } @@ -736,6 +743,13 @@ public class ResultsPanel extends javax.swing.JPanel { @Override protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.WARNING, "Image Worker Exception for file: " + thumbnailWrapper.getResultFile().getFirstInstance().getId(), ex); + } catch (CancellationException ignored) { + //we want to do nothing in response to this since we allow it to be cancelled + } imageThumbnailViewer.repaint(); } @@ -748,7 +762,6 @@ public class ResultsPanel extends javax.swing.JPanel { private class DocumentPreviewWorker extends SwingWorker { private final DocumentWrapper documentWrapper; - private static final int PREVIEW_SIZE = 256; /** * Construct a new DocumentPreviewWorker. @@ -761,55 +774,29 @@ public class ResultsPanel extends javax.swing.JPanel { documentPreviewViewer.addDocument(documentWrapper); } + @Messages({"ResultsPanel.unableToCreate.text=Unable to create summary."}) @Override protected Void doInBackground() throws Exception { - String preview = createPreview(documentWrapper.getResultFile().getFirstInstance()); - if (preview != null) { - documentWrapper.setPreview(preview); + String preview = FileSearch.summarize(documentWrapper.getResultFile().getFirstInstance()); + if (preview == null) { + preview = Bundle.ResultsPanel_unableToCreate_text(); } + documentWrapper.setPreview(preview); return null; } - /** - * Create the string that will be used as the preview for the specified - * AbstractFile. - * - * @param file The AbstractFile to create the preview for. - * - * @return The String which is the preview for the specified - * AbstractFile. - */ - @Messages({"ResultsPanel.documentPreviewWorker.noPreview=No preview available.", - "ResultsPanel.documentPreviewWorker.noBytes=No bytes read for document, unable to display preview."}) - private String createPreview(AbstractFile file) { - byte[] data = new byte[PREVIEW_SIZE]; - int bytesRead = 0; - if (file.getSize() > 0) { - try { - int length = PREVIEW_SIZE > file.getSize() ? (int) file.getSize() : PREVIEW_SIZE; //if the size is less than the int it can be cast to an int - bytesRead = file.read(data, 0, length); // read the data - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error while trying to show the String content.", ex); //NON-NLS - } - } - String text; - if (bytesRead > 0) { - StringExtract stringExtract = new StringExtract(); - final StringExtract.StringExtractUnicodeTable.SCRIPT selScript = StringExtract.StringExtractUnicodeTable.SCRIPT.LATIN_1; - stringExtract.setEnabledScript(selScript); - StringExtract.StringExtractResult res = stringExtract.extract(data, bytesRead, 0); - text = res.getText(); - if (StringUtils.isBlank(text)) { - text = Bundle.ResultsPanel_documentPreviewWorker_noPreview(); - } - } else { - text = Bundle.ResultsPanel_documentPreviewWorker_noBytes(); - } - return text; - } - + @Messages({"ResultsPanel.documentPreview.text=Document preview creation cancelled."}) @Override protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + documentWrapper.setPreview(ex.getMessage()); + logger.log(Level.WARNING, "Document Worker Exception", ex); + } catch (CancellationException ignored) { + documentWrapper.setPreview(Bundle.ResultsPanel_documentPreview_text()); + //we want to do nothing in response to this since we allow it to be cancelled + } documentPreviewViewer.repaint(); } diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form index 4ae16fddf2..7e254689c1 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.form @@ -24,38 +24,36 @@ - + - - - + + - + - + + + - - - - - - - - + + + + + - + @@ -67,7 +65,7 @@ - + @@ -102,4 +100,4 @@ - \ No newline at end of file + diff --git a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java index fdddfa2c62..cff5502e73 100644 --- a/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filequery/VideoThumbnailPanel.java @@ -100,7 +100,7 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe imagePanel = new javax.swing.JPanel(); fileSizeLabel = new javax.swing.JLabel(); - countLabel = new javax.swing.JLabel(); + nameLabel = new javax.swing.JLabel(); scoreLabel = new javax.swing.JLabel(); deletedLabel = new javax.swing.JLabel(); @@ -109,14 +109,14 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe imagePanel.setLayout(new java.awt.GridBagLayout()); scoreLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/red-circle-exclamation.png"))); // NOI18N - scoreLabel.setMaximumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - scoreLabel.setMinimumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - scoreLabel.setPreferredSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); + scoreLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + scoreLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); deletedLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/file-icon-deleted.png"))); // NOI18N - deletedLabel.setMaximumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - deletedLabel.setMinimumSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); - deletedLabel.setPreferredSize(new Dimension(DiscoveryUiUtils.getIconSize(),DiscoveryUiUtils.getIconSize())); + deletedLabel.setMaximumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + deletedLabel.setMinimumSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); + deletedLabel.setPreferredSize(new Dimension(org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize(),org.sleuthkit.autopsy.filequery.DiscoveryUiUtils.getIconSize())); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -127,52 +127,55 @@ final class VideoThumbnailPanel extends javax.swing.JPanel implements ListCellRe .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(imagePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 776, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 248, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(countLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 124, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(deletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(nameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() + .addComponent(nameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(imagePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(deletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(countLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(deletedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(fileSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(scoreLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel countLabel; private javax.swing.JLabel deletedLabel; private javax.swing.JLabel fileSizeLabel; private javax.swing.JPanel imagePanel; + private javax.swing.JLabel nameLabel; private javax.swing.JLabel scoreLabel; // End of variables declaration//GEN-END:variables @Messages({ - "# {0} - numberOfInstances", - "VideoThumbnailPanel.countLabel.text=Number of Instances: {0}", + "# {0} - otherInstanceCount", + "VideoThumbnailPanel.nameLabel.more.text= and {0} more", "VideoThumbnailPanel.deleted.text=All instances of file are deleted."}) @Override public Component getListCellRendererComponent(JList list, VideoThumbnailsWrapper value, int index, boolean isSelected, boolean cellHasFocus) { fileSizeLabel.setText(getFileSizeString(value.getResultFile().getFirstInstance().getSize())); - countLabel.setText(Bundle.VideoThumbnailPanel_countLabel_text(value.getResultFile().getAllInstances().size())); + String nameText = value.getResultFile().getFirstInstance().getParentPath() + value.getResultFile().getFirstInstance().getName(); + if (value.getResultFile().getAllInstances().size() > 1) { + nameText += Bundle.VideoThumbnailPanel_nameLabel_more_text(value.getResultFile().getAllInstances().size() - 1); + } + nameLabel.setText(nameText); addThumbnails(value); imagePanel.setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); DiscoveryUiUtils.setDeletedIcon(value.getResultFile().isDeleted(), deletedLabel); - DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); + DiscoveryUiUtils.setScoreIcon(value.getResultFile(), scoreLabel); setBackground(isSelected ? SELECTION_COLOR : list.getBackground()); return this; } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED index c585d0edf5..0e732c1519 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties-MERGED @@ -14,7 +14,7 @@ KnownStatusSearchPanel.knownCheckBox.text=Known Status: KnownStatusSearchPanel.knownBadOptionCheckBox.text=Notable KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other) KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown -DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected! +DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected\! DateSearchPanel.dateCheckBox.text=Date: DateSearchPanel.jLabel4.text=Timezone: DateSearchPanel.jLabel3.text=*The date format is mm/dd/yyyy @@ -57,7 +57,7 @@ FileSearchPanel.search.results.details=Large number of matches may impact perfor FileSearchPanel.search.exception.noFilterSelected.msg=At least one filter must be selected. FileSearchPanel.search.validationErr.msg=Validation Error: {0} FileSearchPanel.emptyWhereClause.text=Invalid options, nothing to show. -KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected! +KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected\! NameSearchFilter.emptyNameMsg.text=Must enter something for name search. SizeSearchPanel.sizeCompareComboBox.equalTo=equal to SizeSearchPanel.sizeCompareComboBox.greaterThan=greater than diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED index 8e7439fb2f..e5bf351edb 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/geolocation/Bundle.properties-MERGED @@ -30,6 +30,8 @@ GeoTopComponent_no_waypoints_returned_mgs=Applied filter failed to find waypoint GeoTopComponent_no_waypoints_returned_Title=No Waypoints Found GLTopComponent_initilzation_error=An error occurred during waypoint initilization. Geolocation data maybe incomplete. GLTopComponent_name=Geolocation +GLTopComponent_No_dataSource_message=There are no data sources with Geolocation artifacts found. +GLTopComponent_No_dataSource_Title=No Geolocation artifacts found HidingPane_default_title=Filters MapPanel_connection_failure_message=Failed to connect to new geolocation map tile source. MapPanel_connection_failure_message_title=Connection Failure diff --git a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java index e1c4e0773e..cca9382e51 100755 --- a/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/geolocation/GeoFilterPanel.java @@ -52,6 +52,7 @@ class GeoFilterPanel extends javax.swing.JPanel { private final CheckBoxListPanel checkboxPanel; // Make sure to update if + @SuppressWarnings("deprecation") private static final BlackboardArtifact.ARTIFACT_TYPE[] GPS_ARTIFACT_TYPES = { BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK, BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_LAST_KNOWN_LOCATION, diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED index 6be3e48e71..9e4f612b6b 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties-MERGED @@ -140,7 +140,7 @@ IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space IngestJob.cancelReason.servicesDown.text=Services Down IngestJob.cancelReason.caseClosed.text=Case closed IngestJobSettingsPanel.globalSettingsButton.text=Global Settings -gest= +gest IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings IngestJobSettingsPanel.pastJobsButton.text=History diff --git a/Core/src/org/sleuthkit/autopsy/modules/drones/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/drones/Bundle.properties-MERGED index 23f2a02775..bf61ad9be0 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/drones/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/drones/Bundle.properties-MERGED @@ -1,6 +1,6 @@ DATExtractor_process_message=Processing DJI DAT file: %s DATFileExtractor_Extractor_Name=DAT File Extractor -DroneIngestModule_Description=Description -DroneIngestModule_Name=Drone +DroneIngestModule_Description=Analyzes files generated by drones. +DroneIngestModule_Name=Drone Analyzer # {0} - AbstractFileName DroneIngestModule_process_start=Started {0} diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED index 4729293fb9..4585d86449 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties-MERGED @@ -11,7 +11,12 @@ ExtractArchiveWithPasswordAction.progress.text=Unpacking contents of archive: {0 ExtractArchiveWithPasswordAction.prompt.text=Enter Password ExtractArchiveWithPasswordAction.prompt.title=Enter Password OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\nContents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\nIf the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\nThe extracted files are navigable in the directory tree.\n\nThe module is supported on Windows, Linux and Mac operating systems. +OpenIDE-Module-Long-Description=\ + Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\n\ + Contents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\n\ + If the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\n\ + The extracted files are navigable in the directory tree.\n\n\ + The module is supported on Windows, Linux and Mac operating systems. OpenIDE-Module-Name=Embedded File Extraction OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin: {0} @@ -23,7 +28,6 @@ EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg=Possib EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails=Compression ratio is {0}, skipping items in {1}. EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnMsg.zipBomb=Possible ZIP bomb detected: {0} EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb=The archive is {0} levels deep, skipping processing of {1} -EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg=Unknown item path in archive: {0}, will use: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg=Not enough disk space to unpack archive item: {0}, {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details=The archive item is too large to unpack, skipping unpacking this item. EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg=Error unpacking {0} diff --git a/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED index 4915d5a124..f9a5a88b1b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/exif/Bundle.properties-MERGED @@ -2,7 +2,9 @@ CannotRunFileTypeDetection=Cannot run file type detection. ExifParserFileIngestModule.indexError.message=Failed to post EXIF Metadata artifact(s). ExifParserFileIngestModule.userContent.description=EXIF metadata exists for this file. OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Exif metadata ingest module. \n\nThe ingest module analyzes image files, extracts Exif information and posts the Exif data as results. +OpenIDE-Module-Long-Description=\ + Exif metadata ingest module. \n\n\ + The ingest module analyzes image files, extracts Exif information and posts the Exif data as results. OpenIDE-Module-Name=ExifParser OpenIDE-Module-Short-Description=Exif metadata ingest module ExifParserFileIngestModule.moduleName.text=Exif Parser diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED index 5063bd55fa..cfaadf1635 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/Bundle.properties-MERGED @@ -36,27 +36,27 @@ FileExtMismatchSettingsPanel.jLabel1.text=File Types: FileExtMismatchSettingsPanel.newExtButton.text=New Extension FileExtMismatchSettingsPanel.newMimePrompt.message=Add a new MIME file type: FileExtMismatchSettingsPanel.newMimePrompt.title=New MIME -FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty! +FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty\! FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.title=Empty type -FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported! +FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported\! FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.title=Type not supported -FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists! +FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists\! FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.title=Type already exists FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.message=MIME type is not detectable by this module. FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.title=Type not detectable -FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected! +FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected\! FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.title=No type selected FileExtMismatchSettingsPanel.newExtPrompt.message=Add an allowed extension: FileExtMismatchSettingsPanel.newExtPrompt.title=New allowed extension -FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty! +FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty\! FileExtMismatchSettingsPanel.newExtPrompt.empty.title=Extension text empty -FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected! +FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected\! FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.title=No MIME type selected -FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists! +FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists\! FileExtMismatchSettingsPanel.newExtPrompt.extExists.title=Extension already exists -FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected! +FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected\! FileExtMismatchSettingsPanel.removeExtButton.noneSelected.title=No extension selected -FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected! +FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected\! FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.title=No MIME type selected FileExtMismatchSettingsPanel.removeTypeButton.toolTipText= FileExtMismatchModuleSettingsPanel.checkAllRadioButton.text=Check all file types diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED index 44057d0016..0b470ce6b1 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties-MERGED @@ -49,7 +49,10 @@ ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash se ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Hash Set ingest module. \n\nThe ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\nThe module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration. +OpenIDE-Module-Long-Description=\ + Hash Set ingest module. \n\n\ + The ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\n\ + The module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration. OpenIDE-Module-Name=HashDatabases OptionsCategory_Name_HashDatabase=Hash Sets OptionsCategory_Keywords_HashDatabase=Hash Sets @@ -178,7 +181,10 @@ HashDbSearchThread.name.searching=Searching HashDbSearchThread.noMoreFilesWithMD5Msg=No other files with the same MD5 hash were found. ModalNoButtons.indexingDbsTitle=Indexing hash sets ModalNoButtons.indexingDbTitle=Indexing hash set -ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \nThe generated index will be left unusable. If you choose to continue,\nplease delete the corresponding -md5.idx file in the hash folder.\nExit indexing? +ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \n\ +The generated index will be left unusable. If you choose to continue,\n\ + please delete the corresponding -md5.idx file in the hash folder.\n\ + Exit indexing? ModalNoButtons.dlgTitle.unfinishedIndexing=Unfinished Indexing ModalNoButtons.indexThis.currentlyIndexing1Db=Currently indexing 1 hash set ModalNoButtons.indexThese.currentlyIndexing1OfNDbs=Currently indexing 1 of {0} diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED index 31a0690b82..1279d3642b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties-MERGED @@ -83,8 +83,8 @@ FilesSetRulePanel.nameTextField.text= FilesSetRulePanel.ruleNameLabel.text=Rule Name (Optional): FilesSetRulePanel.messages.emptyNameCondition=You must specify a name pattern for this rule. FilesSetRulePanel.messages.invalidNameRegex=The name regular expression is not valid:\n\n{0} -FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, ", <, or > unless it is a regular expression. -FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, ", <, or > unless it is a regular expression. +FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, \", <, or > unless it is a regular expression. +FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, \", <, or > unless it is a regular expression. FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0} FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text=Rule set with name {0} already exists. FilesSetRulePanel.pathSeparatorInfoLabel.text=Folder must be in parent path. Use '/' to give consecutive names diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED index 2dc971a40d..87dacfc16c 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties-MERGED @@ -21,7 +21,7 @@ PhotoRecIngestModule.complete.totalParsetime=Total Parsing Time: PhotoRecIngestModule.complete.photoRecResults=PhotoRec Results PhotoRecIngestModule.NotEnoughDiskSpace.detail.msg=PhotoRec error processing {0} with {1} Not enough space on primary disk to save unallocated space. PhotoRecIngestModule.cancelledByUser=PhotoRec cancelled by user. -PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value = {0} when scanning {1} +PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value \= {0} when scanning {1} PhotoRecIngestModule.error.msg=Error processing {0} with PhotoRec carver. PhotoRecIngestModule.complete.numberOfErrors=Number of Errors while Carving: PhotoRecCarverIngestJobSettingsPanel.detectionSettingsLabel.text=PhotoRec Settings diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/html/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/report/modules/html/Bundle.properties-MERGED index 0be7595111..32f6867f0c 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/html/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/report/modules/html/Bundle.properties-MERGED @@ -5,8 +5,8 @@ ReportHTML.getName.text=HTML Report ReportHTML.getDesc.text=A report about results and tagged items in HTML format. ReportHTML.writeIndex.title=for case {0} ReportHTML.writeIndex.noFrames.msg=Your browser is not compatible with our frame setup. -ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, -ReportHTML.writeIndex.seeSum=and the summary page for a case summary. +ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, +ReportHTML.writeIndex.seeSum=and the summary page for a case summary. ReportHTML.writeNav.title=Report Navigation ReportHTML.writeNav.h1=Report Navigation ReportHTML.writeNav.summary=Case Summary @@ -16,7 +16,7 @@ ReportHTML.writeSum.caseNumber=Case Number: ReportHTML.writeSum.caseNumImages=Number of Images: ReportHTML.writeSum.examiner=Examiner: ReportHTML.writeSum.title=Case Summary -ReportHTML.writeSum.warningMsg=Warning, this report was run before ingest services completed! +ReportHTML.writeSum.warningMsg=Warning, this report was run before ingest services completed\! # # autopsy/test/scripts/regression.py._html_report_diff() uses reportGenOn.text, caseName, caseNum, # examiner as a regex signature to skip report.html and summary.html diff --git a/Core/src/org/sleuthkit/autopsy/textsummarizer/TextSummarizer.java b/Core/src/org/sleuthkit/autopsy/textsummarizer/TextSummarizer.java new file mode 100644 index 0000000000..2d40d7af5b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/textsummarizer/TextSummarizer.java @@ -0,0 +1,48 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019-2020 Basis Technology Corp. + * Contact: carrier sleuthkit 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.textsummarizer; + +import java.io.IOException; +import org.sleuthkit.datamodel.AbstractFile; + +/** + * Interface for implementation of summarizers for documents. + */ +public interface TextSummarizer { + + /** + * Get the name of the TextSummarizer for identification purposes. + * + * @return The name of the TextSummarizer. + */ + String getName(); + + /** + * Summarize the provided abstract file into a summary with a size no + * greater than the size specified. + * + * @param file The AbstractFile to summarize. + * @param summarySize The size of the summary to create. + * + * @return The summary as a string. + * + * @throws IOException + */ + String summarize(AbstractFile file, int summarySize) throws IOException; +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseTestUtils.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseTestUtils.java index 69dcdc71b9..65b47bcb3b 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseTestUtils.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/commonpropertiessearch/InterCaseTestUtils.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2018-2019 Basis Technology Corp. + * Copyright 2018-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -62,6 +62,7 @@ import org.sleuthkit.autopsy.modules.photoreccarver.PhotoRecCarverIngestModuleFa import org.sleuthkit.autopsy.modules.vmextractor.VMExtractorIngestModuleFactory; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepoFactory; /** * Utilities for testing intercase correlation feature. @@ -220,7 +221,7 @@ class InterCaseTestUtils { this.kitchenShink = new IngestJobSettings(InterCaseTestUtils.class.getCanonicalName(), IngestType.ALL_MODULES, kitchenSink); try { - Collection types = CorrelationAttributeInstance.getDefaultCorrelationTypes(); + Collection types = CentralRepository.getInstance().getCorrelationTypes(); //TODO use ids instead of strings FILE_TYPE = types.stream().filter(type -> type.getDisplayName().equals("Files")).findAny().get(); @@ -248,7 +249,7 @@ class InterCaseTestUtils { CentralRepository.getInstance().shutdownConnections(); } FileUtils.deleteDirectory(CENTRAL_REPO_DIRECTORY_PATH.toFile()); - } catch (IOException | CentralRepoExceptionex) { + } catch (IOException | CentralRepoException ex) { Exceptions.printStackTrace(ex); Assert.fail(ex.getMessage()); } @@ -297,8 +298,10 @@ class InterCaseTestUtils { crSettings.createDbDirectory(); } - crSettings.initializeDatabaseSchema(); - crSettings.insertDefaultDatabaseContent(); + RdbmsCentralRepoFactory centralRepoSchemaFactory = new RdbmsCentralRepoFactory(CentralRepoPlatforms.SQLITE, crSettings); + centralRepoSchemaFactory.initializeDatabaseSchema(); + centralRepoSchemaFactory.insertDefaultDatabaseContent(); + crSettings.saveSettings(); CentralRepoPlatforms.setSelectedPlatform(CentralRepoPlatforms.SQLITE.name()); CentralRepoPlatforms.saveSelectedPlatform(); diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index 18deff87f4..ebdce8a327 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -1,7 +1,6 @@ cannotBuildXmlParser=Unable to build XML parser: cannotLoadSEUQA=Unable to load Search Engine URL Query Analyzer settings file, SEUQAMappings.xml: cannotParseXml=Unable to parse XML file: -Chrome.getBookmark.errMsg.errAnalyzeFile={0}: Error while trying to analyze file: {1} ChromeCacheExtract_adding_artifacts_msg=Chrome Cache: Adding %d artifacts for analysis. ChromeCacheExtract_adding_extracted_files_msg=Chrome Cache: Adding %d extracted files for analysis. ChromeCacheExtract_loading_files_msg=Chrome Cache: Loading files from %s. @@ -14,9 +13,9 @@ ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries DataSourceUsage_AndroidMedia=Android Media Card DataSourceUsage_DJU_Drone_DAT=DJI Internal SD Card DataSourceUsage_FlashDrive=Flash Drive +# {0} - OS name DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0}) DataSourceUsageAnalyzer.parentModuleName=Recent Activity -Extract.dbConn.errMsg.failedToQueryDb={0}: Failed to query database. Extract.indexError.message=Failed to index artifact for keyword search. Extract.noOpenCase.errMsg=No open case available. ExtractEdge_getHistory_containerFileNotFound=Error while trying to analyze Edge history @@ -25,11 +24,6 @@ ExtractEdge_process_errMsg_errGettingWebCacheFiles=Error trying to retrieving Ed ExtractEdge_process_errMsg_spartanFail=Failure processing Microsoft Edge spartan.edb file ExtractEdge_process_errMsg_unableFindESEViewer=Unable to find ESEDatabaseViewer ExtractEdge_process_errMsg_webcacheFail=Failure processing Microsoft Edge WebCacheV01.dat file -ExtractIE.getBookmark.ere.noSpace=RecentActivity -ExtractIE.getBookmark.errMsg.errPostingBookmarks=Error posting Internet Explorer Bookmark artifacts. -ExtractIE.getCookie.errMsg.errPostingCookies=Error posting Internet Explorer Cookie artifacts. -ExtractIE.getHistory.errMsg.errPostingHistory=Error posting Internet Explorer History artifacts. -Extractor.errPostingArtifacts=Error posting {0} artifacts to the blackboard. ExtractOs.androidOs.label=Android ExtractOs.androidVolume.label=OS Drive (Android) ExtractOs.debianLinuxOs.label=Linux (Debian) @@ -96,7 +90,7 @@ Chrome.getLogin.errMsg.errAnalyzingFiles={0}: Error while trying to analyze file Chrome.getAutofill.errMsg.errGettingFiles=Error when trying to get Chrome Web Data files. Chrome.getAutofill.errMsg.errAnalyzingFiles={0}: Error while trying to analyze file:{1} ExtractIE.moduleName.text=Internet Explorer -ExtractIE.getBookmark.errMsg.errGettingBookmarks=Error getting Internet Explorer Bookmarks. +ExtractIE.getBookmark.errMsg.errGettingBookmarks={0}: Error getting Internet Explorer Bookmarks. ExtractIE.parentModuleName.noSpace=RecentActivity ExtractIE.parentModuleName=Recent Activity ExtractIE.getURLFromIEBmkFile.errMsg={0}: Error parsing IE bookmark File {1} @@ -198,6 +192,7 @@ RecentDocumentsByLnk.parentModuleName.noSpace=RecentActivity RecentDocumentsByLnk.parentModuleName=Recent Activity RegRipperFullNotFound=Full version RegRipper executable not found. RegRipperNotFound=Autopsy RegRipper executable not found. +# {0} - file name SearchEngineURLQueryAnalyzer.init.exception.msg=Unable to find {0}. SearchEngineURLQueryAnalyzer.moduleName.text=Search Engine SearchEngineURLQueryAnalyzer.engineName.none=NONE diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index b20ccf5912..32871906e7 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Tue, 12 Nov 2019 17:21:46 -0500 +#Thu, 27 Feb 2020 08:01:10 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 @@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18 SplashRunningTextColor=0x0 SplashRunningTextFontSize=19 -currentVersion=Autopsy 4.13.0 +currentVersion=Autopsy 4.14.0 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 998d3f715c..6c1cb1455b 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Tue, 12 Nov 2019 17:21:46 -0500 -CTL_MainWindow_Title=Autopsy 4.13.0 -CTL_MainWindow_Title_No_Project=Autopsy 4.13.0 +#Thu, 27 Feb 2020 08:01:10 -0500 +CTL_MainWindow_Title=Autopsy 4.14.0 +CTL_MainWindow_Title_No_Project=Autopsy 4.14.0